From f91f34339e1c9066c86e50c57fff1945d46898d2 Mon Sep 17 00:00:00 2001 From: David Wolinsky Date: Sat, 18 Mar 2023 14:39:50 -0700 Subject: [PATCH 01/13] [framework] add aptos-token-objects construct the container for aptos-token-objects migrate examples token-objects to framework/aptos-token-objects --- api/src/tests/objects.rs | 4 +- .../src/components/framework.rs | 1 + .../e2e-move-tests/src/tests/token_objects.rs | 2 +- .../framework/aptos-token-objects/Move.toml | 13 + .../aptos-token-objects/doc/aptos_token.md | 1809 +++++++++++++++++ .../aptos-token-objects/doc/collection.md | 727 +++++++ .../aptos-token-objects/doc/overview.md | 22 + .../aptos-token-objects/doc/property_map.md | 953 +++++++++ .../aptos-token-objects/doc/royalty.md | 392 ++++ .../aptos-token-objects/doc/token.md | 799 ++++++++ .../doc_template/overview.md | 7 + .../doc_template/references.md | 1 + .../sources/aptos_token.move | 10 +- .../sources/collection.move | 6 +- .../sources/property_map.move | 2 +- .../aptos-token-objects}/sources/royalty.move | 4 +- .../aptos-token-objects}/sources/token.move | 8 +- .../src/aptos_token_objects_sdk_builder.rs | 664 ++++++ aptos-move/framework/src/aptos.rs | 10 +- aptos-move/framework/tests/move_unit_test.rs | 5 + .../move-examples/token_objects/Move.toml | 1 + .../token_objects/sources/hero.move | 4 +- 22 files changed, 5422 insertions(+), 22 deletions(-) create mode 100644 aptos-move/framework/aptos-token-objects/Move.toml create mode 100644 aptos-move/framework/aptos-token-objects/doc/aptos_token.md create mode 100644 aptos-move/framework/aptos-token-objects/doc/collection.md create mode 100644 aptos-move/framework/aptos-token-objects/doc/overview.md create mode 100644 aptos-move/framework/aptos-token-objects/doc/property_map.md create mode 100644 aptos-move/framework/aptos-token-objects/doc/royalty.md create mode 100644 aptos-move/framework/aptos-token-objects/doc/token.md create mode 100644 aptos-move/framework/aptos-token-objects/doc_template/overview.md create mode 100644 aptos-move/framework/aptos-token-objects/doc_template/references.md rename aptos-move/{move-examples/token_objects => framework/aptos-token-objects}/sources/aptos_token.move (99%) rename aptos-move/{move-examples/token_objects => framework/aptos-token-objects}/sources/collection.move (99%) rename aptos-move/{move-examples/token_objects => framework/aptos-token-objects}/sources/property_map.move (99%) rename aptos-move/{move-examples/token_objects => framework/aptos-token-objects}/sources/royalty.move (98%) rename aptos-move/{move-examples/token_objects => framework/aptos-token-objects}/sources/token.move (98%) create mode 100644 aptos-move/framework/cached-packages/src/aptos_token_objects_sdk_builder.rs diff --git a/api/src/tests/objects.rs b/api/src/tests/objects.rs index 8caae930b669d..74e589f1e5070 100644 --- a/api/src/tests/objects.rs +++ b/api/src/tests/objects.rs @@ -37,7 +37,7 @@ async fn test_gen_object() { let collection_addr = account_address::create_collection_address(user_addr, "Hero Quest!"); let token_addr = account_address::create_token_address(user_addr, "Hero Quest!", "Wukong"); let object_resource = "0x1::object::ObjectCore"; - let token_resource = format!("0x{}::token::Token", user_addr); + let token_resource = "0x4::token::Token"; let hero_resource = format!("0x{}::hero::Hero", user_addr); let collection0 = context.gen_all_resources(&collection_addr).await; @@ -56,7 +56,7 @@ async fn test_gen_object() { let hero = context.gen_all_resources(&token_addr).await; let hero_map = to_object(hero); assert!(hero_map.contains_key(object_resource)); - assert!(hero_map.contains_key(&token_resource)); + assert!(hero_map.contains_key(token_resource)); assert!(hero_map.contains_key(&hero_resource)); let owner: AccountAddress = hero_map[object_resource]["owner"] .as_str() diff --git a/aptos-move/aptos-release-builder/src/components/framework.rs b/aptos-move/aptos-release-builder/src/components/framework.rs index e923005c08b0f..81d721d78c7e9 100644 --- a/aptos-move/aptos-release-builder/src/components/framework.rs +++ b/aptos-move/aptos-release-builder/src/components/framework.rs @@ -30,6 +30,7 @@ pub fn generate_upgrade_proposals( ("0x1", "aptos-move/framework/aptos-stdlib"), ("0x1", "aptos-move/framework/aptos-framework"), ("0x3", "aptos-move/framework/aptos-token"), + ("0x4", "aptos-move/framework/aptos-token-objects"), ]; let mut result: Vec<(String, String)> = vec![]; diff --git a/aptos-move/e2e-move-tests/src/tests/token_objects.rs b/aptos-move/e2e-move-tests/src/tests/token_objects.rs index bdd7881ba089b..7899b52858797 100644 --- a/aptos-move/e2e-move-tests/src/tests/token_objects.rs +++ b/aptos-move/e2e-move-tests/src/tests/token_objects.rs @@ -69,7 +69,7 @@ fn test_basic_token() { type_params: vec![], }; let token_obj_tag = StructTag { - address: addr, + address: AccountAddress::from_hex_literal("0x4").unwrap(), module: Identifier::new("token").unwrap(), name: Identifier::new("Token").unwrap(), type_params: vec![], diff --git a/aptos-move/framework/aptos-token-objects/Move.toml b/aptos-move/framework/aptos-token-objects/Move.toml new file mode 100644 index 0000000000000..c60f18f8d8f40 --- /dev/null +++ b/aptos-move/framework/aptos-token-objects/Move.toml @@ -0,0 +1,13 @@ +[package] +name = "AptosTokenObjects" +version = "1.0.0" + +[addresses] +std = "0x1" +aptos_std = "0x1" +aptos_framework = "0x1" +aptos_token_objects = "0x4" + +[dependencies] +MoveStdlib = { local = "../move-stdlib" } +AptosFramework = { local = "../aptos-framework"} diff --git a/aptos-move/framework/aptos-token-objects/doc/aptos_token.md b/aptos-move/framework/aptos-token-objects/doc/aptos_token.md new file mode 100644 index 0000000000000..eb434cd319cb3 --- /dev/null +++ b/aptos-move/framework/aptos-token-objects/doc/aptos_token.md @@ -0,0 +1,1809 @@ + + + +# Module `0x4::aptos_token` + +This defines a minimally viable token for no-code solutions akin the the original token at +0x3::token module. +The key features are: +* Base token and collection features +* Creator definable mutability for tokens +* Creator-based freezing of tokens +* Standard object-based transfer and events +* Metadata property type + + +- [Resource `AptosCollection`](#0x4_aptos_token_AptosCollection) +- [Resource `AptosToken`](#0x4_aptos_token_AptosToken) +- [Constants](#@Constants_0) +- [Function `create_collection`](#0x4_aptos_token_create_collection) +- [Function `mint`](#0x4_aptos_token_mint) +- [Function `mint_soul_bound`](#0x4_aptos_token_mint_soul_bound) +- [Function `mint_internal`](#0x4_aptos_token_mint_internal) +- [Function `are_properties_mutable`](#0x4_aptos_token_are_properties_mutable) +- [Function `is_burnable`](#0x4_aptos_token_is_burnable) +- [Function `is_freezable_by_creator`](#0x4_aptos_token_is_freezable_by_creator) +- [Function `is_mutable_description`](#0x4_aptos_token_is_mutable_description) +- [Function `is_mutable_name`](#0x4_aptos_token_is_mutable_name) +- [Function `is_mutable_uri`](#0x4_aptos_token_is_mutable_uri) +- [Function `burn`](#0x4_aptos_token_burn) +- [Function `freeze_transfer`](#0x4_aptos_token_freeze_transfer) +- [Function `unfreeze_transfer`](#0x4_aptos_token_unfreeze_transfer) +- [Function `set_description`](#0x4_aptos_token_set_description) +- [Function `set_name`](#0x4_aptos_token_set_name) +- [Function `set_uri`](#0x4_aptos_token_set_uri) +- [Function `add_property`](#0x4_aptos_token_add_property) +- [Function `add_typed_property`](#0x4_aptos_token_add_typed_property) +- [Function `remove_property`](#0x4_aptos_token_remove_property) +- [Function `update_property`](#0x4_aptos_token_update_property) +- [Function `update_typed_property`](#0x4_aptos_token_update_typed_property) +- [Function `burn_call`](#0x4_aptos_token_burn_call) +- [Function `freeze_transfer_call`](#0x4_aptos_token_freeze_transfer_call) +- [Function `unfreeze_transfer_call`](#0x4_aptos_token_unfreeze_transfer_call) +- [Function `set_description_call`](#0x4_aptos_token_set_description_call) +- [Function `set_name_call`](#0x4_aptos_token_set_name_call) +- [Function `set_uri_call`](#0x4_aptos_token_set_uri_call) +- [Function `add_property_call`](#0x4_aptos_token_add_property_call) +- [Function `add_typed_property_call`](#0x4_aptos_token_add_typed_property_call) +- [Function `remove_property_call`](#0x4_aptos_token_remove_property_call) +- [Function `update_property_call`](#0x4_aptos_token_update_property_call) +- [Function `update_typed_property_call`](#0x4_aptos_token_update_typed_property_call) +- [Function `is_mutable_collection_description`](#0x4_aptos_token_is_mutable_collection_description) +- [Function `is_mutable_collection_royalty`](#0x4_aptos_token_is_mutable_collection_royalty) +- [Function `is_mutable_collection_uri`](#0x4_aptos_token_is_mutable_collection_uri) +- [Function `is_mutable_collection_token_description`](#0x4_aptos_token_is_mutable_collection_token_description) +- [Function `is_mutable_collection_token_name`](#0x4_aptos_token_is_mutable_collection_token_name) +- [Function `is_mutable_collection_token_uri`](#0x4_aptos_token_is_mutable_collection_token_uri) +- [Function `is_mutable_collection_token_properties`](#0x4_aptos_token_is_mutable_collection_token_properties) +- [Function `are_collection_tokens_burnable`](#0x4_aptos_token_are_collection_tokens_burnable) +- [Function `are_collection_tokens_freezable`](#0x4_aptos_token_are_collection_tokens_freezable) +- [Function `set_collection_description`](#0x4_aptos_token_set_collection_description) +- [Function `set_collection_royalties`](#0x4_aptos_token_set_collection_royalties) +- [Function `set_collection_uri`](#0x4_aptos_token_set_collection_uri) +- [Function `set_collection_description_call`](#0x4_aptos_token_set_collection_description_call) +- [Function `set_collection_royalties_call`](#0x4_aptos_token_set_collection_royalties_call) +- [Function `set_collection_uri_call`](#0x4_aptos_token_set_collection_uri_call) + + +
use 0x1::error;
+use 0x1::object;
+use 0x1::option;
+use 0x1::signer;
+use 0x1::string;
+use 0x4::collection;
+use 0x4::property_map;
+use 0x4::royalty;
+use 0x4::token;
+
+ + + + + +## Resource `AptosCollection` + +Storage state for managing the no-code Collection. + + +
struct AptosCollection has key
+
+ + + +
+Fields + + +
+
+mutator_ref: option::Option<collection::MutatorRef> +
+
+ Used to mutate collection fields +
+
+royalty_mutator_ref: option::Option<royalty::MutatorRef> +
+
+ Used to mutate royalties +
+
+mutable_description: bool +
+
+ Determines if the creator can mutate the collection's description +
+
+mutable_uri: bool +
+
+ Determines if the creator can mutate the collection's uri +
+
+mutable_token_description: bool +
+
+ Determines if the creator can mutate token descriptions +
+
+mutable_token_name: bool +
+
+ Determines if the creator can mutate token names +
+
+mutable_token_properties: bool +
+
+ Determines if the creator can mutate token properties +
+
+mutable_token_uri: bool +
+
+ Determines if the creator can mutate token uris +
+
+tokens_burnable_by_creator: bool +
+
+ Determines if the creator can burn tokens +
+
+tokens_freezable_by_creator: bool +
+
+ Determines if the creator can freeze tokens +
+
+ + +
+ + + +## Resource `AptosToken` + +Storage state for managing the no-code Token. + + +
struct AptosToken has key
+
+ + + +
+Fields + + +
+
+burn_ref: option::Option<token::BurnRef> +
+
+ Used to burn. +
+
+transfer_ref: option::Option<object::TransferRef> +
+
+ Used to control freeze. +
+
+mutator_ref: option::Option<token::MutatorRef> +
+
+ Used to mutate fields +
+
+property_mutator_ref: option::Option<property_map::MutatorRef> +
+
+ Used to mutate properties +
+
+ + +
+ + + +## Constants + + + + + + +
const ECOLLECTION_DOES_NOT_EXIST: u64 = 1;
+
+ + + + + +Attempted to mutate an immutable field + + +
const EFIELD_NOT_MUTABLE: u64 = 3;
+
+ + + + + +The provided signer is not the creator + + +
const ENOT_CREATOR: u64 = 2;
+
+ + + + + + + +
const ETOKEN_DOES_NOT_EXIST: u64 = 1;
+
+ + + + + +Attempted to mutate a property map that is not mutable + + +
const EPROPERTIES_NOT_MUTABLE: u64 = 5;
+
+ + + + + +Attempted to burn a non-burnable token + + +
const ETOKEN_NOT_BURNABLE: u64 = 4;
+
+ + + + + +## Function `create_collection` + +Create a new collection + + +
public entry fun create_collection(creator: &signer, description: string::String, max_supply: u64, name: string::String, uri: string::String, mutable_description: bool, mutable_royalty: bool, mutable_uri: bool, mutable_token_description: bool, mutable_token_name: bool, mutable_token_properties: bool, mutable_token_uri: bool, tokens_burnable_by_creator: bool, tokens_freezable_by_creator: bool, royalty_numerator: u64, royalty_denominator: u64)
+
+ + + +
+Implementation + + +
public entry fun create_collection(
+    creator: &signer,
+    description: String,
+    max_supply: u64,
+    name: String,
+    uri: String,
+    mutable_description: bool,
+    mutable_royalty: bool,
+    mutable_uri: bool,
+    mutable_token_description: bool,
+    mutable_token_name: bool,
+    mutable_token_properties: bool,
+    mutable_token_uri: bool,
+    tokens_burnable_by_creator: bool,
+    tokens_freezable_by_creator: bool,
+    royalty_numerator: u64,
+    royalty_denominator: u64,
+) {
+    let creator_addr = signer::address_of(creator);
+    let royalty = royalty::create(royalty_numerator, royalty_denominator, creator_addr);
+    let constructor_ref = collection::create_fixed_collection(
+        creator,
+        description,
+        max_supply,
+        name,
+        option::some(royalty),
+        uri,
+    );
+
+    let object_signer = object::generate_signer(&constructor_ref);
+    let mutator_ref = if (mutable_description || mutable_uri) {
+        option::some(collection::generate_mutator_ref(&constructor_ref))
+    } else {
+        option::none()
+    };
+
+    let royalty_mutator_ref = if (mutable_royalty) {
+        option::some(royalty::generate_mutator_ref(object::generate_extend_ref(&constructor_ref)))
+    } else {
+        option::none()
+    };
+
+    let aptos_collection = AptosCollection {
+        mutator_ref,
+        royalty_mutator_ref,
+        mutable_description,
+        mutable_uri,
+        mutable_token_description,
+        mutable_token_name,
+        mutable_token_properties,
+        mutable_token_uri,
+        tokens_burnable_by_creator,
+        tokens_freezable_by_creator,
+    };
+    move_to(&object_signer, aptos_collection);
+}
+
+ + + +
+ + + +## Function `mint` + +With an existing collection, directly mint a viable token into the creators account. + + +
public entry fun mint(creator: &signer, collection: string::String, description: string::String, name: string::String, uri: string::String, property_keys: vector<string::String>, property_types: vector<string::String>, property_values: vector<vector<u8>>)
+
+ + + +
+Implementation + + +
public entry fun mint(
+    creator: &signer,
+    collection: String,
+    description: String,
+    name: String,
+    uri: String,
+    property_keys: vector<String>,
+    property_types: vector<String>,
+    property_values: vector<vector<u8>>,
+) acquires AptosCollection, AptosToken {
+    let constructor_ref = mint_internal(
+        creator,
+        collection,
+        description,
+        name,
+        uri,
+        property_keys,
+        property_types,
+        property_values,
+    );
+
+    let collection = collection_object(creator, &collection);
+    let freezable_by_creator = are_collection_tokens_freezable(collection);
+    if (!freezable_by_creator) {
+        return
+    };
+
+    let aptos_token_addr = object::address_from_constructor_ref(&constructor_ref);
+    let aptos_token = borrow_global_mut<AptosToken>(aptos_token_addr);
+    let transfer_ref = object::generate_transfer_ref(&constructor_ref);
+    option::fill(&mut aptos_token.transfer_ref, transfer_ref);
+}
+
+ + + +
+ + + +## Function `mint_soul_bound` + +With an existing collection, directly mint a soul bound token into the recipient's account. + + +
public entry fun mint_soul_bound(creator: &signer, collection: string::String, description: string::String, name: string::String, uri: string::String, property_keys: vector<string::String>, property_types: vector<string::String>, property_values: vector<vector<u8>>, soul_bound_to: address)
+
+ + + +
+Implementation + + +
public entry fun mint_soul_bound(
+    creator: &signer,
+    collection: String,
+    description: String,
+    name: String,
+    uri: String,
+    property_keys: vector<String>,
+    property_types: vector<String>,
+    property_values: vector<vector<u8>>,
+    soul_bound_to: address,
+) acquires AptosCollection {
+    let constructor_ref = mint_internal(
+        creator,
+        collection,
+        description,
+        name,
+        uri,
+        property_keys,
+        property_types,
+        property_values,
+    );
+
+    let transfer_ref = object::generate_transfer_ref(&constructor_ref);
+    let linear_transfer_ref = object::generate_linear_transfer_ref(&transfer_ref);
+    object::transfer_with_ref(linear_transfer_ref, soul_bound_to);
+    object::disable_ungated_transfer(&transfer_ref);
+}
+
+ + + +
+ + + +## Function `mint_internal` + + + +
fun mint_internal(creator: &signer, collection: string::String, description: string::String, name: string::String, uri: string::String, property_keys: vector<string::String>, property_types: vector<string::String>, property_values: vector<vector<u8>>): object::ConstructorRef
+
+ + + +
+Implementation + + +
fun mint_internal(
+    creator: &signer,
+    collection: String,
+    description: String,
+    name: String,
+    uri: String,
+    property_keys: vector<String>,
+    property_types: vector<String>,
+    property_values: vector<vector<u8>>,
+): ConstructorRef acquires AptosCollection {
+    let constructor_ref = token::create(
+        creator,
+        collection,
+        description,
+        name,
+        option::none(),
+        uri,
+    );
+
+    let object_signer = object::generate_signer(&constructor_ref);
+
+    let collection_obj = collection_object(creator, &collection);
+    let collection = borrow_collection(&collection_obj);
+
+    let mutator_ref = if (
+        collection.mutable_token_description
+        || collection.mutable_token_name
+        || collection.mutable_token_uri
+    ) {
+        option::some(token::generate_mutator_ref(&constructor_ref))
+    } else {
+        option::none()
+    };
+
+    let burn_ref = if (collection.tokens_burnable_by_creator) {
+        option::some(token::generate_burn_ref(&constructor_ref))
+    } else {
+        option::none()
+    };
+
+    let property_mutator_ref = if (collection.mutable_token_properties) {
+        option::some(property_map::generate_mutator_ref(&constructor_ref))
+    } else {
+        option::none()
+    };
+
+    let aptos_token = AptosToken {
+        burn_ref,
+        transfer_ref: option::none(),
+        mutator_ref,
+        property_mutator_ref,
+    };
+    move_to(&object_signer, aptos_token);
+
+    let properties = property_map::prepare_input(property_keys, property_types, property_values);
+    property_map::init(&constructor_ref, properties);
+
+    constructor_ref
+}
+
+ + + +
+ + + +## Function `are_properties_mutable` + + + +
public fun are_properties_mutable<T: key>(token: object::Object<T>): bool
+
+ + + +
+Implementation + + +
public fun are_properties_mutable<T: key>(token: Object<T>): bool acquires AptosToken {
+    option::is_some(&borrow(&token).property_mutator_ref)
+}
+
+ + + +
+ + + +## Function `is_burnable` + + + +
public fun is_burnable<T: key>(token: object::Object<T>): bool
+
+ + + +
+Implementation + + +
public fun is_burnable<T: key>(token: Object<T>): bool acquires AptosToken {
+    option::is_some(&borrow(&token).burn_ref)
+}
+
+ + + +
+ + + +## Function `is_freezable_by_creator` + + + +
public fun is_freezable_by_creator<T: key>(token: object::Object<T>): bool
+
+ + + +
+Implementation + + +
public fun is_freezable_by_creator<T: key>(token: Object<T>): bool acquires AptosCollection {
+    are_collection_tokens_freezable(token::collection_object(token))
+}
+
+ + + +
+ + + +## Function `is_mutable_description` + + + +
public fun is_mutable_description<T: key>(token: object::Object<T>): bool
+
+ + + +
+Implementation + + +
public fun is_mutable_description<T: key>(token: Object<T>): bool acquires AptosCollection {
+    is_mutable_collection_token_description(token::collection_object(token))
+}
+
+ + + +
+ + + +## Function `is_mutable_name` + + + +
public fun is_mutable_name<T: key>(token: object::Object<T>): bool
+
+ + + +
+Implementation + + +
public fun is_mutable_name<T: key>(token: Object<T>): bool acquires AptosCollection {
+    is_mutable_collection_token_name(token::collection_object(token))
+}
+
+ + + +
+ + + +## Function `is_mutable_uri` + + + +
public fun is_mutable_uri<T: key>(token: object::Object<T>): bool
+
+ + + +
+Implementation + + +
public fun is_mutable_uri<T: key>(token: Object<T>): bool acquires AptosCollection {
+    is_mutable_collection_token_uri(token::collection_object(token))
+}
+
+ + + +
+ + + +## Function `burn` + + + +
public fun burn<T: key>(creator: &signer, token: object::Object<T>)
+
+ + + +
+Implementation + + +
public fun burn<T: key>(creator: &signer, token: Object<T>) acquires AptosToken {
+    let aptos_token = authorized_borrow(&token, signer::address_of(creator));
+    assert!(
+        option::is_some(&aptos_token.burn_ref),
+        error::permission_denied(ETOKEN_NOT_BURNABLE),
+    );
+    move aptos_token;
+    let aptos_token = move_from<AptosToken>(object::object_address(&token));
+    let AptosToken {
+        burn_ref,
+        transfer_ref: _,
+        mutator_ref: _,
+        property_mutator_ref: _,
+    } = aptos_token;
+    token::burn(option::extract(&mut burn_ref));
+}
+
+ + + +
+ + + +## Function `freeze_transfer` + + + +
public fun freeze_transfer<T: key>(creator: &signer, token: object::Object<T>)
+
+ + + +
+Implementation + + +
public fun freeze_transfer<T: key>(creator: &signer, token: Object<T>) acquires AptosCollection, AptosToken {
+    assert!(
+        are_collection_tokens_freezable(token::collection_object(token)),
+        error::permission_denied(EFIELD_NOT_MUTABLE),
+    );
+    let aptos_token = authorized_borrow(&token, signer::address_of(creator));
+    object::disable_ungated_transfer(option::borrow(&aptos_token.transfer_ref));
+}
+
+ + + +
+ + + +## Function `unfreeze_transfer` + + + +
public fun unfreeze_transfer<T: key>(creator: &signer, token: object::Object<T>)
+
+ + + +
+Implementation + + +
public fun unfreeze_transfer<T: key>(creator: &signer, token: Object<T>) acquires AptosCollection, AptosToken {
+    assert!(
+        are_collection_tokens_freezable(token::collection_object(token)),
+        error::permission_denied(EFIELD_NOT_MUTABLE),
+    );
+    let aptos_token = authorized_borrow(&token, signer::address_of(creator));
+    object::enable_ungated_transfer(option::borrow(&aptos_token.transfer_ref));
+}
+
+ + + +
+ + + +## Function `set_description` + + + +
public fun set_description<T: key>(creator: &signer, token: object::Object<T>, description: string::String)
+
+ + + +
+Implementation + + +
public fun set_description<T: key>(
+    creator: &signer,
+    token: Object<T>,
+    description: String,
+) acquires AptosCollection, AptosToken {
+    assert!(
+        is_mutable_description(token),
+        error::permission_denied(EFIELD_NOT_MUTABLE),
+    );
+    let aptos_token = authorized_borrow(&token, signer::address_of(creator));
+    token::set_description(option::borrow(&aptos_token.mutator_ref), description);
+}
+
+ + + +
+ + + +## Function `set_name` + + + +
public fun set_name<T: key>(creator: &signer, token: object::Object<T>, name: string::String)
+
+ + + +
+Implementation + + +
public fun set_name<T: key>(
+    creator: &signer,
+    token: Object<T>,
+    name: String,
+) acquires AptosCollection, AptosToken {
+    assert!(
+        is_mutable_name(token),
+        error::permission_denied(EFIELD_NOT_MUTABLE),
+    );
+    let aptos_token = authorized_borrow(&token, signer::address_of(creator));
+    token::set_name(option::borrow(&aptos_token.mutator_ref), name);
+}
+
+ + + +
+ + + +## Function `set_uri` + + + +
public fun set_uri<T: key>(creator: &signer, token: object::Object<T>, uri: string::String)
+
+ + + +
+Implementation + + +
public fun set_uri<T: key>(
+    creator: &signer,
+    token: Object<T>,
+    uri: String,
+) acquires AptosCollection, AptosToken {
+    assert!(
+        is_mutable_uri(token),
+        error::permission_denied(EFIELD_NOT_MUTABLE),
+    );
+    let aptos_token = authorized_borrow(&token, signer::address_of(creator));
+    token::set_uri(option::borrow(&aptos_token.mutator_ref), uri);
+}
+
+ + + +
+ + + +## Function `add_property` + + + +
public fun add_property<T: key>(creator: &signer, token: object::Object<T>, key: string::String, type: string::String, value: vector<u8>)
+
+ + + +
+Implementation + + +
public fun add_property<T: key>(
+    creator: &signer,
+    token: Object<T>,
+    key: String,
+    type: String,
+    value: vector<u8>,
+) acquires AptosToken {
+    let aptos_token = authorized_borrow(&token, signer::address_of(creator));
+    assert!(
+        option::is_some(&aptos_token.property_mutator_ref),
+        error::permission_denied(EPROPERTIES_NOT_MUTABLE),
+    );
+
+    property_map::add(
+        option::borrow(&aptos_token.property_mutator_ref),
+        key,
+        type,
+        value,
+    );
+}
+
+ + + +
+ + + +## Function `add_typed_property` + + + +
public fun add_typed_property<T: key, V: drop>(creator: &signer, token: object::Object<T>, key: string::String, value: V)
+
+ + + +
+Implementation + + +
public fun add_typed_property<T: key, V: drop>(
+    creator: &signer,
+    token: Object<T>,
+    key: String,
+    value: V,
+) acquires AptosToken {
+    let aptos_token = authorized_borrow(&token, signer::address_of(creator));
+    assert!(
+        option::is_some(&aptos_token.property_mutator_ref),
+        error::permission_denied(EPROPERTIES_NOT_MUTABLE),
+    );
+
+    property_map::add_typed(
+        option::borrow(&aptos_token.property_mutator_ref),
+        key,
+        value,
+    );
+}
+
+ + + +
+ + + +## Function `remove_property` + + + +
public fun remove_property<T: key>(creator: &signer, token: object::Object<T>, key: &string::String)
+
+ + + +
+Implementation + + +
public fun remove_property<T: key>(creator: &signer, token: Object<T>, key: &String) acquires AptosToken {
+    let aptos_token = authorized_borrow(&token, signer::address_of(creator));
+    assert!(
+        option::is_some(&aptos_token.property_mutator_ref),
+        error::permission_denied(EPROPERTIES_NOT_MUTABLE),
+    );
+
+    property_map::remove(option::borrow(&aptos_token.property_mutator_ref), key);
+}
+
+ + + +
+ + + +## Function `update_property` + + + +
public fun update_property<T: key>(creator: &signer, token: object::Object<T>, key: &string::String, type: string::String, value: vector<u8>)
+
+ + + +
+Implementation + + +
public fun update_property<T: key>(
+    creator: &signer,
+    token: Object<T>,
+    key: &String,
+    type: String,
+    value: vector<u8>,
+) acquires AptosToken {
+    let aptos_token = authorized_borrow(&token, signer::address_of(creator));
+    assert!(
+        option::is_some(&aptos_token.property_mutator_ref),
+        error::permission_denied(EPROPERTIES_NOT_MUTABLE),
+    );
+
+    property_map::update(
+        option::borrow(&aptos_token.property_mutator_ref),
+        key,
+        type,
+        value,
+    );
+}
+
+ + + +
+ + + +## Function `update_typed_property` + + + +
public fun update_typed_property<T: key, V: drop>(creator: &signer, token: object::Object<T>, key: &string::String, value: V)
+
+ + + +
+Implementation + + +
public fun update_typed_property<T: key, V: drop>(
+    creator: &signer,
+    token: Object<T>,
+    key: &String,
+    value: V,
+) acquires AptosToken {
+    let aptos_token = authorized_borrow(&token, signer::address_of(creator));
+    assert!(
+        option::is_some(&aptos_token.property_mutator_ref),
+        error::permission_denied(EPROPERTIES_NOT_MUTABLE),
+    );
+
+    property_map::update_typed(
+        option::borrow(&aptos_token.property_mutator_ref),
+        key,
+        value,
+    );
+}
+
+ + + +
+ + + +## Function `burn_call` + + + +
entry fun burn_call(creator: &signer, collection: string::String, name: string::String)
+
+ + + +
+Implementation + + +
entry fun burn_call(
+    creator: &signer,
+    collection: String,
+    name: String,
+) acquires AptosToken {
+    burn(creator, token_object(creator, &collection, &name));
+}
+
+ + + +
+ + + +## Function `freeze_transfer_call` + + + +
entry fun freeze_transfer_call(creator: &signer, collection: string::String, name: string::String)
+
+ + + +
+Implementation + + +
entry fun freeze_transfer_call(
+    creator: &signer,
+    collection: String,
+    name: String,
+) acquires AptosCollection, AptosToken {
+    freeze_transfer(creator, token_object(creator, &collection, &name));
+}
+
+ + + +
+ + + +## Function `unfreeze_transfer_call` + + + +
entry fun unfreeze_transfer_call(creator: &signer, collection: string::String, name: string::String)
+
+ + + +
+Implementation + + +
entry fun unfreeze_transfer_call(
+    creator: &signer,
+    collection: String,
+    name: String,
+) acquires AptosCollection, AptosToken {
+    unfreeze_transfer(creator, token_object(creator, &collection, &name));
+}
+
+ + + +
+ + + +## Function `set_description_call` + + + +
entry fun set_description_call(creator: &signer, collection: string::String, name: string::String, description: string::String)
+
+ + + +
+Implementation + + +
entry fun set_description_call(
+    creator: &signer,
+    collection: String,
+    name: String,
+    description: String,
+) acquires AptosCollection, AptosToken {
+    set_description(creator, token_object(creator, &collection, &name), description);
+}
+
+ + + +
+ + + +## Function `set_name_call` + + + +
entry fun set_name_call(creator: &signer, collection: string::String, original_name: string::String, new_name: string::String)
+
+ + + +
+Implementation + + +
entry fun set_name_call(
+    creator: &signer,
+    collection: String,
+    original_name: String,
+    new_name: String,
+) acquires AptosCollection, AptosToken {
+    set_name(creator, token_object(creator, &collection, &original_name), new_name);
+}
+
+ + + +
+ + + +## Function `set_uri_call` + + + +
entry fun set_uri_call(creator: &signer, collection: string::String, name: string::String, uri: string::String)
+
+ + + +
+Implementation + + +
entry fun set_uri_call(
+    creator: &signer,
+    collection: String,
+    name: String,
+    uri: String,
+) acquires AptosCollection, AptosToken {
+    set_uri(creator, token_object(creator, &collection, &name), uri);
+}
+
+ + + +
+ + + +## Function `add_property_call` + + + +
entry fun add_property_call(creator: &signer, collection: string::String, name: string::String, key: string::String, type: string::String, value: vector<u8>)
+
+ + + +
+Implementation + + +
entry fun add_property_call(
+    creator: &signer,
+    collection: String,
+    name: String,
+    key: String,
+    type: String,
+    value: vector<u8>,
+) acquires AptosToken {
+    let token = token_object(creator, &collection, &name);
+    add_property(creator, token, key, type, value);
+}
+
+ + + +
+ + + +## Function `add_typed_property_call` + + + +
entry fun add_typed_property_call<T: drop>(creator: &signer, collection: string::String, name: string::String, key: string::String, value: T)
+
+ + + +
+Implementation + + +
entry fun add_typed_property_call<T: drop>(
+    creator: &signer,
+    collection: String,
+    name: String,
+    key: String,
+    value: T,
+) acquires AptosToken {
+    let token = token_object(creator, &collection, &name);
+    add_typed_property(creator, token, key, value);
+}
+
+ + + +
+ + + +## Function `remove_property_call` + + + +
entry fun remove_property_call(creator: &signer, collection: string::String, name: string::String, key: string::String)
+
+ + + +
+Implementation + + +
entry fun remove_property_call(
+    creator: &signer,
+    collection: String,
+    name: String,
+    key: String,
+) acquires AptosToken {
+    let token = token_object(creator, &collection, &name);
+    remove_property(creator, token, &key);
+}
+
+ + + +
+ + + +## Function `update_property_call` + + + +
entry fun update_property_call(creator: &signer, collection: string::String, name: string::String, key: string::String, type: string::String, value: vector<u8>)
+
+ + + +
+Implementation + + +
entry fun update_property_call(
+    creator: &signer,
+    collection: String,
+    name: String,
+    key: String,
+    type: String,
+    value: vector<u8>,
+) acquires AptosToken {
+    let token = token_object(creator, &collection, &name);
+    update_property(creator, token, &key, type, value);
+}
+
+ + + +
+ + + +## Function `update_typed_property_call` + + + +
entry fun update_typed_property_call<T: drop>(creator: &signer, collection: string::String, name: string::String, key: string::String, value: T)
+
+ + + +
+Implementation + + +
entry fun update_typed_property_call<T: drop>(
+    creator: &signer,
+    collection: String,
+    name: String,
+    key: String,
+    value: T,
+) acquires AptosToken {
+    let token = token_object(creator, &collection, &name);
+    update_typed_property(creator, token, &key, value);
+}
+
+ + + +
+ + + +## Function `is_mutable_collection_description` + + + +
public fun is_mutable_collection_description<T: key>(collection: object::Object<T>): bool
+
+ + + +
+Implementation + + +
public fun is_mutable_collection_description<T: key>(
+    collection: Object<T>,
+): bool acquires AptosCollection {
+    borrow_collection(&collection).mutable_description
+}
+
+ + + +
+ + + +## Function `is_mutable_collection_royalty` + + + +
public fun is_mutable_collection_royalty<T: key>(collection: object::Object<T>): bool
+
+ + + +
+Implementation + + +
public fun is_mutable_collection_royalty<T: key>(
+    collection: Object<T>,
+): bool acquires AptosCollection {
+    option::is_some(&borrow_collection(&collection).royalty_mutator_ref)
+}
+
+ + + +
+ + + +## Function `is_mutable_collection_uri` + + + +
public fun is_mutable_collection_uri<T: key>(collection: object::Object<T>): bool
+
+ + + +
+Implementation + + +
public fun is_mutable_collection_uri<T: key>(
+    collection: Object<T>,
+): bool acquires AptosCollection {
+    borrow_collection(&collection).mutable_uri
+}
+
+ + + +
+ + + +## Function `is_mutable_collection_token_description` + + + +
public fun is_mutable_collection_token_description<T: key>(collection: object::Object<T>): bool
+
+ + + +
+Implementation + + +
public fun is_mutable_collection_token_description<T: key>(
+    collection: Object<T>,
+): bool acquires AptosCollection {
+    borrow_collection(&collection).mutable_token_description
+}
+
+ + + +
+ + + +## Function `is_mutable_collection_token_name` + + + +
public fun is_mutable_collection_token_name<T: key>(collection: object::Object<T>): bool
+
+ + + +
+Implementation + + +
public fun is_mutable_collection_token_name<T: key>(
+    collection: Object<T>,
+): bool acquires AptosCollection {
+    borrow_collection(&collection).mutable_token_name
+}
+
+ + + +
+ + + +## Function `is_mutable_collection_token_uri` + + + +
public fun is_mutable_collection_token_uri<T: key>(collection: object::Object<T>): bool
+
+ + + +
+Implementation + + +
public fun is_mutable_collection_token_uri<T: key>(
+    collection: Object<T>,
+): bool acquires AptosCollection {
+    borrow_collection(&collection).mutable_token_uri
+}
+
+ + + +
+ + + +## Function `is_mutable_collection_token_properties` + + + +
public fun is_mutable_collection_token_properties<T: key>(collection: object::Object<T>): bool
+
+ + + +
+Implementation + + +
public fun is_mutable_collection_token_properties<T: key>(
+    collection: Object<T>,
+): bool acquires AptosCollection {
+    borrow_collection(&collection).mutable_token_properties
+}
+
+ + + +
+ + + +## Function `are_collection_tokens_burnable` + + + +
public fun are_collection_tokens_burnable<T: key>(collection: object::Object<T>): bool
+
+ + + +
+Implementation + + +
public fun are_collection_tokens_burnable<T: key>(
+    collection: Object<T>,
+): bool acquires AptosCollection {
+    borrow_collection(&collection).tokens_burnable_by_creator
+}
+
+ + + +
+ + + +## Function `are_collection_tokens_freezable` + + + +
public fun are_collection_tokens_freezable<T: key>(collection: object::Object<T>): bool
+
+ + + +
+Implementation + + +
public fun are_collection_tokens_freezable<T: key>(
+    collection: Object<T>,
+): bool acquires AptosCollection {
+    borrow_collection(&collection).tokens_freezable_by_creator
+}
+
+ + + +
+ + + +## Function `set_collection_description` + + + +
public fun set_collection_description<T: key>(creator: &signer, collection: object::Object<T>, description: string::String)
+
+ + + +
+Implementation + + +
public fun set_collection_description<T: key>(
+    creator: &signer,
+    collection: Object<T>,
+    description: String,
+) acquires AptosCollection {
+    let aptos_collection = authorized_borrow_collection(&collection, signer::address_of(creator));
+    assert!(
+        aptos_collection.mutable_description,
+        error::permission_denied(EFIELD_NOT_MUTABLE),
+    );
+    collection::set_description(option::borrow(&aptos_collection.mutator_ref), description);
+}
+
+ + + +
+ + + +## Function `set_collection_royalties` + + + +
public fun set_collection_royalties<T: key>(creator: &signer, collection: object::Object<T>, royalty: royalty::Royalty)
+
+ + + +
+Implementation + + +
public fun set_collection_royalties<T: key>(
+    creator: &signer,
+    collection: Object<T>,
+    royalty: royalty::Royalty,
+) acquires AptosCollection {
+    let aptos_collection = authorized_borrow_collection(&collection, signer::address_of(creator));
+    assert!(
+        option::is_some(&aptos_collection.royalty_mutator_ref),
+        error::permission_denied(EFIELD_NOT_MUTABLE),
+    );
+    royalty::update(option::borrow(&aptos_collection.royalty_mutator_ref), royalty);
+}
+
+ + + +
+ + + +## Function `set_collection_uri` + + + +
public fun set_collection_uri<T: key>(creator: &signer, collection: object::Object<T>, uri: string::String)
+
+ + + +
+Implementation + + +
public fun set_collection_uri<T: key>(
+    creator: &signer,
+    collection: Object<T>,
+    uri: String,
+) acquires AptosCollection {
+    let aptos_collection = authorized_borrow_collection(&collection, signer::address_of(creator));
+    assert!(
+        aptos_collection.mutable_uri,
+        error::permission_denied(EFIELD_NOT_MUTABLE),
+    );
+    collection::set_uri(option::borrow(&aptos_collection.mutator_ref), uri);
+}
+
+ + + +
+ + + +## Function `set_collection_description_call` + + + +
entry fun set_collection_description_call(creator: &signer, collection: string::String, description: string::String)
+
+ + + +
+Implementation + + +
entry fun set_collection_description_call(
+    creator: &signer,
+    collection: String,
+    description: String,
+) acquires AptosCollection {
+    set_collection_description(creator, collection_object(creator, &collection), description);
+}
+
+ + + +
+ + + +## Function `set_collection_royalties_call` + + + +
entry fun set_collection_royalties_call(creator: &signer, collection: string::String, royalty_numerator: u64, royalty_denominator: u64, payee_address: address)
+
+ + + +
+Implementation + + +
entry fun set_collection_royalties_call(
+    creator: &signer,
+    collection: String,
+    royalty_numerator: u64,
+    royalty_denominator: u64,
+    payee_address: address,
+) acquires AptosCollection {
+    let royalty = royalty::create(royalty_numerator, royalty_denominator, payee_address);
+    set_collection_royalties(creator, collection_object(creator, &collection), royalty);
+}
+
+ + + +
+ + + +## Function `set_collection_uri_call` + + + +
entry fun set_collection_uri_call(creator: &signer, collection: string::String, uri: string::String)
+
+ + + +
+Implementation + + +
entry fun set_collection_uri_call(
+    creator: &signer,
+    collection: String,
+    uri: String,
+) acquires AptosCollection {
+    set_collection_uri(creator, collection_object(creator, &collection), uri);
+}
+
+ + + +
+ + +[move-book]: https://move-language.github.io/move/introduction.html diff --git a/aptos-move/framework/aptos-token-objects/doc/collection.md b/aptos-move/framework/aptos-token-objects/doc/collection.md new file mode 100644 index 0000000000000..e64db7a33f243 --- /dev/null +++ b/aptos-move/framework/aptos-token-objects/doc/collection.md @@ -0,0 +1,727 @@ + + + +# Module `0x4::collection` + +This defines an object-based Collection. A collection acts as a set organizer for a group of +tokens. This includes aspects such as a general description, project URI, name, and may contain +other useful generalizations across this set of tokens. + +Being built upon objects enables collections to be relatively flexible. As core primitives it +supports: +* Common fields: name, uri, description, creator +* MutatorRef leaving mutability configuration to a higher level component +* Addressed by a global identifier of creator's address and collection name, thus collections +cannot be deleted as a restriction of the object model. +* Optional support for collection-wide royalties +* Optional support for tracking of supply + +This collection does not directly support: +* Events on mint or burn -- that's left to the collection creator. + +TODO: +* Consider supporting changing the name of the collection with the MutatorRef. This would +require adding the field original_name. +* Consider supporting changing the aspects of supply with the MutatorRef. +* Add aggregator support when added to framework +* Update Object to be viable input as a transaction arg and then update all readers as view. + + +- [Resource `Collection`](#0x4_collection_Collection) +- [Struct `MutationEvent`](#0x4_collection_MutationEvent) +- [Struct `MutatorRef`](#0x4_collection_MutatorRef) +- [Resource `FixedSupply`](#0x4_collection_FixedSupply) +- [Constants](#@Constants_0) +- [Function `create_fixed_collection`](#0x4_collection_create_fixed_collection) +- [Function `create_untracked_collection`](#0x4_collection_create_untracked_collection) +- [Function `create_collection_address`](#0x4_collection_create_collection_address) +- [Function `create_collection_seed`](#0x4_collection_create_collection_seed) +- [Function `increment_supply`](#0x4_collection_increment_supply) +- [Function `decrement_supply`](#0x4_collection_decrement_supply) +- [Function `create_collection`](#0x4_collection_create_collection) +- [Function `generate_mutator_ref`](#0x4_collection_generate_mutator_ref) +- [Function `count`](#0x4_collection_count) +- [Function `creator`](#0x4_collection_creator) +- [Function `description`](#0x4_collection_description) +- [Function `name`](#0x4_collection_name) +- [Function `uri`](#0x4_collection_uri) +- [Function `set_description`](#0x4_collection_set_description) +- [Function `set_uri`](#0x4_collection_set_uri) + + +
use 0x1::error;
+use 0x1::event;
+use 0x1::object;
+use 0x1::option;
+use 0x1::signer;
+use 0x1::string;
+use 0x4::royalty;
+
+ + + + + +## Resource `Collection` + +Represents the common fields for a collection. + + +
struct Collection has key
+
+ + + +
+Fields + + +
+
+creator: address +
+
+ The creator of this collection. +
+
+description: string::String +
+
+ A brief description of the collection. +
+
+name: string::String +
+
+ An optional categorization of similar token. +
+
+uri: string::String +
+
+ The Uniform Resource Identifier (uri) pointing to the JSON file stored in off-chain + storage; the URL length will likely need a maximum any suggestions? +
+
+mutation_events: event::EventHandle<collection::MutationEvent> +
+
+ Emitted upon any mutation of the collection. +
+
+ + +
+ + + +## Struct `MutationEvent` + +Contains the mutated fields name. This makes the life of indexers easier, so that they can +directly understand the behavior in a writeset. + + +
struct MutationEvent has drop, store
+
+ + + +
+Fields + + +
+
+mutated_field_name: string::String +
+
+ +
+
+ + +
+ + + +## Struct `MutatorRef` + +This enables mutating description and URI by higher level services. + + +
struct MutatorRef has drop, store
+
+ + + +
+Fields + + +
+
+self: address +
+
+ +
+
+ + +
+ + + +## Resource `FixedSupply` + +Fixed supply tracker, this is useful for ensuring that a limited number of tokens are minted. + + +
struct FixedSupply has key
+
+ + + +
+Fields + + +
+
+current_supply: u64 +
+
+ +
+
+max_supply: u64 +
+
+ +
+
+total_minted: u64 +
+
+ +
+
+ + +
+ + + +## Constants + + + + +The collection does not exist + + +
const ECOLLECTION_DOES_NOT_EXIST: u64 = 2;
+
+ + + + + +The collections supply is at its maximum amount + + +
const EEXCEEDS_MAX_SUPPLY: u64 = 1;
+
+ + + + + +## Function `create_fixed_collection` + +Creates a fixed-sized collection, or a collection that supports a fixed amount of tokens. +This is useful to create a guaranteed, limited supply on-chain digital asset. For example, +a collection 1111 vicious vipers. Note, creating restrictions such as upward limits results +in data structures that prevent Aptos from parallelizing mints of this collection type. + + +
public fun create_fixed_collection(creator: &signer, description: string::String, max_supply: u64, name: string::String, royalty: option::Option<royalty::Royalty>, uri: string::String): object::ConstructorRef
+
+ + + +
+Implementation + + +
public fun create_fixed_collection(
+    creator: &signer,
+    description: String,
+    max_supply: u64,
+    name: String,
+    royalty: Option<Royalty>,
+    uri: String,
+): ConstructorRef {
+    let supply = FixedSupply {
+        current_supply: 0,
+        max_supply,
+        total_minted: 0,
+    };
+
+    create_collection_internal(
+        creator,
+        description,
+        name,
+        royalty,
+        uri,
+        option::some(supply),
+    )
+}
+
+ + + +
+ + + +## Function `create_untracked_collection` + +Creates an untracked collection, or a collection that supports an arbitrary amount of +tokens. This is useful for mass airdrops that fully leverage Aptos parallelization. + + +
public fun create_untracked_collection(creator: &signer, description: string::String, name: string::String, royalty: option::Option<royalty::Royalty>, uri: string::String): object::ConstructorRef
+
+ + + +
+Implementation + + +
public fun create_untracked_collection(
+    creator: &signer,
+    description: String,
+    name: String,
+    royalty: Option<Royalty>,
+    uri: String,
+): ConstructorRef {
+    create_collection_internal<FixedSupply>(
+        creator,
+        description,
+        name,
+        royalty,
+        uri,
+        option::none(),
+    )
+}
+
+ + + +
+ + + +## Function `create_collection_address` + +Generates the collections address based upon the creators address and the collection's name + + +
public fun create_collection_address(creator: &address, name: &string::String): address
+
+ + + +
+Implementation + + +
public fun create_collection_address(creator: &address, name: &String): address {
+    object::create_object_address(creator, create_collection_seed(name))
+}
+
+ + + +
+ + + +## Function `create_collection_seed` + +Named objects are derived from a seed, the collection's seed is its name. + + +
public fun create_collection_seed(name: &string::String): vector<u8>
+
+ + + +
+Implementation + + +
public fun create_collection_seed(name: &String): vector<u8> {
+    *string::bytes(name)
+}
+
+ + + +
+ + + +## Function `increment_supply` + +Called by token on mint to increment supply if there's an appropriate Supply struct. + + +
public(friend) fun increment_supply(collection: &object::Object<collection::Collection>): option::Option<u64>
+
+ + + +
+Implementation + + +
public(friend) fun increment_supply(
+    collection: &Object<Collection>,
+): Option<u64> acquires FixedSupply {
+    let collection_addr = object::object_address(collection);
+    if (exists<FixedSupply>(collection_addr)) {
+        let supply = borrow_global_mut<FixedSupply>(collection_addr);
+        supply.current_supply = supply.current_supply + 1;
+        supply.total_minted = supply.total_minted + 1;
+        assert!(
+            supply.current_supply <= supply.max_supply,
+            error::out_of_range(EEXCEEDS_MAX_SUPPLY),
+        );
+        option::some(supply.total_minted)
+    } else {
+        option::none()
+    }
+}
+
+ + + +
+ + + +## Function `decrement_supply` + +Called by token on burn to decrement supply if there's an appropriate Supply struct. + + +
public(friend) fun decrement_supply(collection: &object::Object<collection::Collection>)
+
+ + + +
+Implementation + + +
public(friend) fun decrement_supply(collection: &Object<Collection>) acquires FixedSupply {
+    let collection_addr = object::object_address(collection);
+    if (exists<FixedSupply>(collection_addr)) {
+        let supply = borrow_global_mut<FixedSupply>(collection_addr);
+        supply.current_supply = supply.current_supply - 1;
+    }
+}
+
+ + + +
+ + + +## Function `create_collection` + +Entry function for creating a collection + + +
public entry fun create_collection(creator: &signer, description: string::String, name: string::String, uri: string::String, max_supply: u64, enable_royalty: bool, royalty_numerator: u64, royalty_denominator: u64, royalty_payee_address: address)
+
+ + + +
+Implementation + + +
public entry fun create_collection(
+    creator: &signer,
+    description: String,
+    name: String,
+    uri: String,
+    max_supply: u64,
+    enable_royalty: bool,
+    royalty_numerator: u64,
+    royalty_denominator: u64,
+    royalty_payee_address: address,
+) {
+    let royalty = if (enable_royalty) {
+        option::some(royalty::create(
+            royalty_numerator,
+            royalty_denominator,
+            royalty_payee_address,
+        ))
+    } else {
+        option::none()
+    };
+
+    if (max_supply == 0) {
+        create_untracked_collection(
+            creator,
+            description,
+            name,
+            royalty,
+            uri,
+        )
+    } else {
+        create_fixed_collection(
+            creator,
+            description,
+            max_supply,
+            name,
+            royalty,
+            uri,
+        )
+    };
+}
+
+ + + +
+ + + +## Function `generate_mutator_ref` + +Creates a MutatorRef, which gates the ability to mutate any fields that support mutation. + + +
public fun generate_mutator_ref(ref: &object::ConstructorRef): collection::MutatorRef
+
+ + + +
+Implementation + + +
public fun generate_mutator_ref(ref: &ConstructorRef): MutatorRef {
+    let object = object::object_from_constructor_ref<Collection>(ref);
+    MutatorRef { self: object::object_address(&object) }
+}
+
+ + + +
+ + + +## Function `count` + + + +
public fun count<T: key>(collection: object::Object<T>): option::Option<u64>
+
+ + + +
+Implementation + + +
public fun count<T: key>(collection: Object<T>): Option<u64> acquires FixedSupply {
+    let collection_address = object::object_address(&collection);
+    assert!(
+        exists<Collection>(collection_address),
+        error::not_found(ECOLLECTION_DOES_NOT_EXIST),
+    );
+
+    if (exists<FixedSupply>(collection_address)) {
+        let supply = borrow_global_mut<FixedSupply>(collection_address);
+        option::some(supply.current_supply)
+    } else {
+        option::none()
+    }
+}
+
+ + + +
+ + + +## Function `creator` + + + +
public fun creator<T: key>(collection: object::Object<T>): address
+
+ + + +
+Implementation + + +
public fun creator<T: key>(collection: Object<T>): address acquires Collection {
+    borrow(&collection).creator
+}
+
+ + + +
+ + + +## Function `description` + + + +
public fun description<T: key>(collection: object::Object<T>): string::String
+
+ + + +
+Implementation + + +
public fun description<T: key>(collection: Object<T>): String acquires Collection {
+    borrow(&collection).description
+}
+
+ + + +
+ + + +## Function `name` + + + +
public fun name<T: key>(collection: object::Object<T>): string::String
+
+ + + +
+Implementation + + +
public fun name<T: key>(collection: Object<T>): String acquires Collection {
+    borrow(&collection).name
+}
+
+ + + +
+ + + +## Function `uri` + + + +
public fun uri<T: key>(collection: object::Object<T>): string::String
+
+ + + +
+Implementation + + +
public fun uri<T: key>(collection: Object<T>): String acquires Collection {
+    borrow(&collection).uri
+}
+
+ + + +
+ + + +## Function `set_description` + + + +
public fun set_description(mutator_ref: &collection::MutatorRef, description: string::String)
+
+ + + +
+Implementation + + +
public fun set_description(
+    mutator_ref: &MutatorRef,
+    description: String,
+) acquires Collection {
+    let collection = borrow_mut(mutator_ref);
+    collection.description = description;
+    event::emit_event(
+        &mut collection.mutation_events,
+        MutationEvent { mutated_field_name: string::utf8(b"description") },
+    );
+}
+
+ + + +
+ + + +## Function `set_uri` + + + +
public fun set_uri(mutator_ref: &collection::MutatorRef, uri: string::String)
+
+ + + +
+Implementation + + +
public fun set_uri(
+    mutator_ref: &MutatorRef,
+    uri: String,
+) acquires Collection {
+    let collection = borrow_mut(mutator_ref);
+    collection.uri = uri;
+    event::emit_event(
+        &mut collection.mutation_events,
+        MutationEvent { mutated_field_name: string::utf8(b"uri") },
+    );
+}
+
+ + + +
+ + +[move-book]: https://move-language.github.io/move/introduction.html diff --git a/aptos-move/framework/aptos-token-objects/doc/overview.md b/aptos-move/framework/aptos-token-objects/doc/overview.md new file mode 100644 index 0000000000000..95871073813d9 --- /dev/null +++ b/aptos-move/framework/aptos-token-objects/doc/overview.md @@ -0,0 +1,22 @@ + + + +# Aptos Token Framework + + +This is the reference documentation of the Aptos Token Objects framework. + + + + +## Index + + +- [`0x4::aptos_token`](aptos_token.md#0x4_aptos_token) +- [`0x4::collection`](collection.md#0x4_collection) +- [`0x4::property_map`](property_map.md#0x4_property_map) +- [`0x4::royalty`](royalty.md#0x4_royalty) +- [`0x4::token`](token.md#0x4_token) + + +[move-book]: https://move-language.github.io/move/introduction.html diff --git a/aptos-move/framework/aptos-token-objects/doc/property_map.md b/aptos-move/framework/aptos-token-objects/doc/property_map.md new file mode 100644 index 0000000000000..4115b702df9b5 --- /dev/null +++ b/aptos-move/framework/aptos-token-objects/doc/property_map.md @@ -0,0 +1,953 @@ + + + +# Module `0x4::property_map` + +PropertyMap provides generic metadata support for AptosToken. It is a specialization of +SimpleMap that enforces strict typing with minimal storage use by using constant u64 to +represent types and storing values in bcs format. + + +- [Resource `PropertyMap`](#0x4_property_map_PropertyMap) +- [Struct `PropertyValue`](#0x4_property_map_PropertyValue) +- [Struct `MutatorRef`](#0x4_property_map_MutatorRef) +- [Constants](#@Constants_0) +- [Function `init`](#0x4_property_map_init) +- [Function `prepare_input`](#0x4_property_map_prepare_input) +- [Function `generate_mutator_ref`](#0x4_property_map_generate_mutator_ref) +- [Function `contains_key`](#0x4_property_map_contains_key) +- [Function `length`](#0x4_property_map_length) +- [Function `read`](#0x4_property_map_read) +- [Function `read_bool`](#0x4_property_map_read_bool) +- [Function `read_u8`](#0x4_property_map_read_u8) +- [Function `read_u16`](#0x4_property_map_read_u16) +- [Function `read_u32`](#0x4_property_map_read_u32) +- [Function `read_u64`](#0x4_property_map_read_u64) +- [Function `read_u128`](#0x4_property_map_read_u128) +- [Function `read_u256`](#0x4_property_map_read_u256) +- [Function `read_address`](#0x4_property_map_read_address) +- [Function `read_bytes`](#0x4_property_map_read_bytes) +- [Function `read_string`](#0x4_property_map_read_string) +- [Function `add`](#0x4_property_map_add) +- [Function `add_typed`](#0x4_property_map_add_typed) +- [Function `add_internal`](#0x4_property_map_add_internal) +- [Function `update`](#0x4_property_map_update) +- [Function `update_typed`](#0x4_property_map_update_typed) +- [Function `update_internal`](#0x4_property_map_update_internal) +- [Function `remove`](#0x4_property_map_remove) + + +
use 0x1::bcs;
+use 0x1::error;
+use 0x1::from_bcs;
+use 0x1::object;
+use 0x1::simple_map;
+use 0x1::string;
+use 0x1::type_info;
+use 0x1::vector;
+
+ + + + + +## Resource `PropertyMap` + + + +
struct PropertyMap has key
+
+ + + +
+Fields + + +
+
+inner: simple_map::SimpleMap<string::String, property_map::PropertyValue> +
+
+ +
+
+ + +
+ + + +## Struct `PropertyValue` + + + +
struct PropertyValue has drop, store
+
+ + + +
+Fields + + +
+
+type: u8 +
+
+ +
+
+value: vector<u8> +
+
+ +
+
+ + +
+ + + +## Struct `MutatorRef` + + + +
struct MutatorRef has drop, store
+
+ + + +
+Fields + + +
+
+self: address +
+
+ +
+
+ + +
+ + + +## Constants + + + + +Property type does not match + + +
const ETYPE_MISMATCH: u64 = 5;
+
+ + + + + + + +
const ADDRESS: u8 = 7;
+
+ + + + + + + +
const BOOL: u8 = 0;
+
+ + + + + + + +
const BYTE_VECTOR: u8 = 8;
+
+ + + + + +The property key already exists + + +
const EKEY_AREADY_EXIST_IN_PROPERTY_MAP: u64 = 1;
+
+ + + + + +Property key and type count do not match + + +
const EKEY_TYPE_COUNT_MISMATCH: u64 = 4;
+
+ + + + + +Property key and value counts do not match + + +
const EKEY_VALUE_COUNT_MISMATCH: u64 = 3;
+
+ + + + + +The property map does not exist within global storage + + +
const EPROPERTY_MAP_DOES_NOT_EXIST: u64 = 7;
+
+ + + + + +The name (key) of the property is too long + + +
const EPROPERTY_MAP_NAME_TOO_LONG: u64 = 6;
+
+ + + + + +The number of property exceeds the limit + + +
const EPROPERTY_NUMBER_EXCEEDS_LIMIT: u64 = 2;
+
+ + + + + +Invalid type specified + + +
const ETYPE_INVALID: u64 = 8;
+
+ + + + + + + +
const MAX_PROPERTY_MAP_SIZE: u64 = 1000;
+
+ + + + + + + +
const MAX_PROPERTY_NAME_LENGTH: u64 = 128;
+
+ + + + + + + +
const STRING: u8 = 9;
+
+ + + + + + + +
const U128: u8 = 5;
+
+ + + + + + + +
const U16: u8 = 2;
+
+ + + + + + + +
const U256: u8 = 6;
+
+ + + + + + + +
const U32: u8 = 3;
+
+ + + + + + + +
const U64: u8 = 4;
+
+ + + + + + + +
const U8: u8 = 1;
+
+ + + + + +## Function `init` + + + +
public fun init(ref: &object::ConstructorRef, container: property_map::PropertyMap)
+
+ + + +
+Implementation + + +
public fun init(ref: &ConstructorRef, container: PropertyMap) {
+    let signer = object::generate_signer(ref);
+    move_to(&signer, container);
+}
+
+ + + +
+ + + +## Function `prepare_input` + +Helper for external entry functions to produce a valid container for property values. + + +
public fun prepare_input(keys: vector<string::String>, types: vector<string::String>, values: vector<vector<u8>>): property_map::PropertyMap
+
+ + + +
+Implementation + + +
public fun prepare_input(
+    keys: vector<String>,
+    types: vector<String>,
+    values: vector<vector<u8>>,
+): PropertyMap {
+    let length = vector::length(&keys);
+    assert!(length <= MAX_PROPERTY_MAP_SIZE, error::invalid_argument(EPROPERTY_NUMBER_EXCEEDS_LIMIT));
+    assert!(length == vector::length(&values), error::invalid_argument(EKEY_VALUE_COUNT_MISMATCH));
+    assert!(length == vector::length(&types), error::invalid_argument(EKEY_TYPE_COUNT_MISMATCH));
+
+    let container = simple_map::create<String, PropertyValue>();
+    while (!vector::is_empty(&keys)) {
+        let key = vector::pop_back(&mut keys);
+        assert!(
+            string::length(&key) <= MAX_PROPERTY_NAME_LENGTH,
+            error::invalid_argument(EPROPERTY_MAP_NAME_TOO_LONG),
+        );
+
+        let value = vector::pop_back(&mut values);
+        let type = vector::pop_back(&mut types);
+
+        let new_type = to_internal_type(type);
+        validate_type(new_type, value);
+
+        simple_map::add(&mut container, key, PropertyValue { value, type: new_type });
+    };
+
+    PropertyMap { inner: container }
+}
+
+ + + +
+ + + +## Function `generate_mutator_ref` + + + +
public fun generate_mutator_ref(ref: &object::ConstructorRef): property_map::MutatorRef
+
+ + + +
+Implementation + + +
public fun generate_mutator_ref(ref: &ConstructorRef): MutatorRef {
+    MutatorRef { self: object::address_from_constructor_ref(ref) }
+}
+
+ + + +
+ + + +## Function `contains_key` + + + +
public fun contains_key<T: key>(object: &object::Object<T>, key: &string::String): bool
+
+ + + +
+Implementation + + +
public fun contains_key<T: key>(object: &Object<T>, key: &String): bool acquires PropertyMap {
+    assert!(
+        exists<PropertyMap>(object::object_address(object)),
+        error::not_found(EPROPERTY_MAP_DOES_NOT_EXIST),
+    );
+    let property_map = borrow_global<PropertyMap>(object::object_address(object));
+    simple_map::contains_key(&property_map.inner, key)
+}
+
+ + + +
+ + + +## Function `length` + + + +
public fun length<T: key>(object: &object::Object<T>): u64
+
+ + + +
+Implementation + + +
public fun length<T: key>(object: &Object<T>): u64 acquires PropertyMap {
+    assert!(
+        exists<PropertyMap>(object::object_address(object)),
+        error::not_found(EPROPERTY_MAP_DOES_NOT_EXIST),
+    );
+    let property_map = borrow_global<PropertyMap>(object::object_address(object));
+    simple_map::length(&property_map.inner)
+}
+
+ + + +
+ + + +## Function `read` + + + +
public fun read<T: key>(object: &object::Object<T>, key: &string::String): (string::String, vector<u8>)
+
+ + + +
+Implementation + + +
public fun read<T: key>(object: &Object<T>, key: &String): (String, vector<u8>) acquires PropertyMap {
+    assert!(
+        exists<PropertyMap>(object::object_address(object)),
+        error::not_found(EPROPERTY_MAP_DOES_NOT_EXIST),
+    );
+    let property_map = borrow_global<PropertyMap>(object::object_address(object));
+    let property_value = simple_map::borrow(&property_map.inner, key);
+    let new_type = to_external_type(property_value.type);
+    (new_type, property_value.value)
+}
+
+ + + +
+ + + +## Function `read_bool` + + + +
public fun read_bool<T: key>(object: &object::Object<T>, key: &string::String): bool
+
+ + + +
+Implementation + + +
public fun read_bool<T: key>(object: &Object<T>, key: &String): bool acquires PropertyMap {
+    let value = read_typed<T, bool>(object, key);
+    from_bcs::to_bool(value)
+}
+
+ + + +
+ + + +## Function `read_u8` + + + +
public fun read_u8<T: key>(object: &object::Object<T>, key: &string::String): u8
+
+ + + +
+Implementation + + +
public fun read_u8<T: key>(object: &Object<T>, key: &String): u8 acquires PropertyMap {
+    let value = read_typed<T, u8>(object, key);
+    from_bcs::to_u8(value)
+}
+
+ + + +
+ + + +## Function `read_u16` + + + +
public fun read_u16<T: key>(object: &object::Object<T>, key: &string::String): u16
+
+ + + +
+Implementation + + +
public fun read_u16<T: key>(object: &Object<T>, key: &String): u16 acquires PropertyMap {
+    let value = read_typed<T, u16>(object, key);
+    from_bcs::to_u16(value)
+}
+
+ + + +
+ + + +## Function `read_u32` + + + +
public fun read_u32<T: key>(object: &object::Object<T>, key: &string::String): u32
+
+ + + +
+Implementation + + +
public fun read_u32<T: key>(object: &Object<T>, key: &String): u32 acquires PropertyMap {
+    let value = read_typed<T, u32>(object, key);
+    from_bcs::to_u32(value)
+}
+
+ + + +
+ + + +## Function `read_u64` + + + +
public fun read_u64<T: key>(object: &object::Object<T>, key: &string::String): u64
+
+ + + +
+Implementation + + +
public fun read_u64<T: key>(object: &Object<T>, key: &String): u64 acquires PropertyMap {
+    let value = read_typed<T, u64>(object, key);
+    from_bcs::to_u64(value)
+}
+
+ + + +
+ + + +## Function `read_u128` + + + +
public fun read_u128<T: key>(object: &object::Object<T>, key: &string::String): u128
+
+ + + +
+Implementation + + +
public fun read_u128<T: key>(object: &Object<T>, key: &String): u128 acquires PropertyMap {
+    let value = read_typed<T, u128>(object, key);
+    from_bcs::to_u128(value)
+}
+
+ + + +
+ + + +## Function `read_u256` + + + +
public fun read_u256<T: key>(object: &object::Object<T>, key: &string::String): u256
+
+ + + +
+Implementation + + +
public fun read_u256<T: key>(object: &Object<T>, key: &String): u256 acquires PropertyMap {
+    let value = read_typed<T, u256>(object, key);
+    from_bcs::to_u256(value)
+}
+
+ + + +
+ + + +## Function `read_address` + + + +
public fun read_address<T: key>(object: &object::Object<T>, key: &string::String): address
+
+ + + +
+Implementation + + +
public fun read_address<T: key>(object: &Object<T>, key: &String): address acquires PropertyMap {
+    let value = read_typed<T, address>(object, key);
+    from_bcs::to_address(value)
+}
+
+ + + +
+ + + +## Function `read_bytes` + + + +
public fun read_bytes<T: key>(object: &object::Object<T>, key: &string::String): vector<u8>
+
+ + + +
+Implementation + + +
public fun read_bytes<T: key>(object: &Object<T>, key: &String): vector<u8>acquires PropertyMap {
+    let value = read_typed<T, vector<u8>>(object, key);
+    from_bcs::to_bytes(value)
+}
+
+ + + +
+ + + +## Function `read_string` + + + +
public fun read_string<T: key>(object: &object::Object<T>, key: &string::String): string::String
+
+ + + +
+Implementation + + +
public fun read_string<T: key>(object: &Object<T>, key: &String): String acquires PropertyMap {
+    let value = read_typed<T, String>(object, key);
+    from_bcs::to_string(value)
+}
+
+ + + +
+ + + +## Function `add` + + + +
public fun add(ref: &property_map::MutatorRef, key: string::String, type: string::String, value: vector<u8>)
+
+ + + +
+Implementation + + +
public fun add(ref: &MutatorRef, key: String, type: String, value: vector<u8>) acquires PropertyMap {
+    let new_type = to_internal_type(type);
+    validate_type(new_type, value);
+    add_internal(ref, key, new_type, value);
+}
+
+ + + +
+ + + +## Function `add_typed` + + + +
public fun add_typed<T: drop>(ref: &property_map::MutatorRef, key: string::String, value: T)
+
+ + + +
+Implementation + + +
public fun add_typed<T: drop>(ref: &MutatorRef, key: String, value: T) acquires PropertyMap {
+    let type = type_info_to_internal_type<T>();
+    add_internal(ref, key, type, bcs::to_bytes(&value));
+}
+
+ + + +
+ + + +## Function `add_internal` + + + +
fun add_internal(ref: &property_map::MutatorRef, key: string::String, type: u8, value: vector<u8>)
+
+ + + +
+Implementation + + +
fun add_internal(ref: &MutatorRef, key: String, type: u8, value: vector<u8>) acquires PropertyMap {
+    assert!(exists<PropertyMap>(ref.self), error::not_found(EPROPERTY_MAP_DOES_NOT_EXIST));
+    let property_map = borrow_global_mut<PropertyMap>(ref.self);
+    simple_map::add(&mut property_map.inner, key, PropertyValue { type, value });
+}
+
+ + + +
+ + + +## Function `update` + + + +
public fun update(ref: &property_map::MutatorRef, key: &string::String, type: string::String, value: vector<u8>)
+
+ + + +
+Implementation + + +
public fun update(ref: &MutatorRef, key: &String, type: String, value: vector<u8>) acquires PropertyMap {
+    let new_type = to_internal_type(type);
+    validate_type(new_type, value);
+    update_internal(ref, key, new_type, value);
+}
+
+ + + +
+ + + +## Function `update_typed` + + + +
public fun update_typed<T: drop>(ref: &property_map::MutatorRef, key: &string::String, value: T)
+
+ + + +
+Implementation + + +
public fun update_typed<T: drop>(ref: &MutatorRef, key: &String, value: T) acquires PropertyMap {
+    let type = type_info_to_internal_type<T>();
+    update_internal(ref, key, type, bcs::to_bytes(&value));
+}
+
+ + + +
+ + + +## Function `update_internal` + + + +
fun update_internal(ref: &property_map::MutatorRef, key: &string::String, type: u8, value: vector<u8>)
+
+ + + +
+Implementation + + +
fun update_internal(ref: &MutatorRef, key: &String, type: u8, value: vector<u8>) acquires PropertyMap {
+    assert!(exists<PropertyMap>(ref.self), error::not_found(EPROPERTY_MAP_DOES_NOT_EXIST));
+    let property_map = borrow_global_mut<PropertyMap>(ref.self);
+    let old_value = simple_map::borrow_mut(&mut property_map.inner, key);
+    *old_value = PropertyValue { type, value };
+}
+
+ + + +
+ + + +## Function `remove` + + + +
public fun remove(ref: &property_map::MutatorRef, key: &string::String)
+
+ + + +
+Implementation + + +
public fun remove(ref: &MutatorRef, key: &String) acquires PropertyMap {
+    assert!(exists<PropertyMap>(ref.self), error::not_found(EPROPERTY_MAP_DOES_NOT_EXIST));
+    let property_map = borrow_global_mut<PropertyMap>(ref.self);
+    simple_map::remove(&mut property_map.inner, key);
+}
+
+ + + +
+ + +[move-book]: https://move-language.github.io/move/introduction.html diff --git a/aptos-move/framework/aptos-token-objects/doc/royalty.md b/aptos-move/framework/aptos-token-objects/doc/royalty.md new file mode 100644 index 0000000000000..520a259eb7e52 --- /dev/null +++ b/aptos-move/framework/aptos-token-objects/doc/royalty.md @@ -0,0 +1,392 @@ + + + +# Module `0x4::royalty` + +This defines an object-based Royalty. The royalty can be applied to either a collection or a +token. Applications should read the royalty from the token, as it will read the appropriate +royalty. + + +- [Resource `Royalty`](#0x4_royalty_Royalty) +- [Struct `MutatorRef`](#0x4_royalty_MutatorRef) +- [Constants](#@Constants_0) +- [Function `init`](#0x4_royalty_init) +- [Function `update`](#0x4_royalty_update) +- [Function `create`](#0x4_royalty_create) +- [Function `generate_mutator_ref`](#0x4_royalty_generate_mutator_ref) +- [Function `exists_at`](#0x4_royalty_exists_at) +- [Function `delete`](#0x4_royalty_delete) +- [Function `get`](#0x4_royalty_get) +- [Function `denominator`](#0x4_royalty_denominator) +- [Function `numerator`](#0x4_royalty_numerator) +- [Function `payee_address`](#0x4_royalty_payee_address) + + +
use 0x1::error;
+use 0x1::object;
+use 0x1::option;
+
+ + + + + +## Resource `Royalty` + +The royalty of a token within this collection -- this optional + + +
struct Royalty has copy, drop, key
+
+ + + +
+Fields + + +
+
+numerator: u64 +
+
+ +
+
+denominator: u64 +
+
+ +
+
+payee_address: address +
+
+ The recipient of royalty payments. See the shared_account for how to handle multiple + creators. +
+
+ + +
+ + + +## Struct `MutatorRef` + + + +
struct MutatorRef has drop, store
+
+ + + +
+Fields + + +
+
+inner: object::ExtendRef +
+
+ +
+
+ + +
+ + + +## Constants + + + + + + +
const EROYALTY_DENOMINATOR_IS_ZERO: u64 = 2;
+
+ + + + + + + +
const EROYALTY_DOES_NOT_EXIST: u64 = 3;
+
+ + + + + + + +
const EROYALTY_EXCEEDS_MAXIMUM: u64 = 1;
+
+ + + + + +## Function `init` + +Add a royalty, given a ConstructorRef. + + +
public fun init(ref: &object::ConstructorRef, royalty: royalty::Royalty)
+
+ + + +
+Implementation + + +
public fun init(ref: &ConstructorRef, royalty: Royalty) {
+    let signer = object::generate_signer(ref);
+    move_to(&signer, royalty);
+}
+
+ + + +
+ + + +## Function `update` + +Set the royalty if it does not exist, replace it otherwise. + + +
public fun update(mutator_ref: &royalty::MutatorRef, royalty: royalty::Royalty)
+
+ + + +
+Implementation + + +
public fun update(mutator_ref: &MutatorRef, royalty: Royalty) acquires Royalty {
+    let addr = object::address_from_extend_ref(&mutator_ref.inner);
+    if (exists<Royalty>(addr)) {
+        move_from<Royalty>(addr);
+    };
+
+    let signer = object::generate_signer_for_extending(&mutator_ref.inner);
+    move_to(&signer, royalty);
+}
+
+ + + +
+ + + +## Function `create` + + + +
public fun create(numerator: u64, denominator: u64, payee_address: address): royalty::Royalty
+
+ + + +
+Implementation + + +
public fun create(numerator: u64, denominator: u64, payee_address: address): Royalty {
+    assert!(denominator != 0, error::out_of_range(EROYALTY_DENOMINATOR_IS_ZERO));
+    assert!(numerator <= denominator, error::out_of_range(EROYALTY_EXCEEDS_MAXIMUM));
+
+    Royalty { numerator, denominator, payee_address }
+}
+
+ + + +
+ + + +## Function `generate_mutator_ref` + + + +
public fun generate_mutator_ref(ref: object::ExtendRef): royalty::MutatorRef
+
+ + + +
+Implementation + + +
public fun generate_mutator_ref(ref: ExtendRef): MutatorRef {
+    MutatorRef { inner: ref }
+}
+
+ + + +
+ + + +## Function `exists_at` + + + +
public fun exists_at(addr: address): bool
+
+ + + +
+Implementation + + +
public fun exists_at(addr: address): bool {
+    exists<Royalty>(addr)
+}
+
+ + + +
+ + + +## Function `delete` + + + +
public(friend) fun delete(addr: address)
+
+ + + +
+Implementation + + +
public(friend) fun delete(addr: address) acquires Royalty {
+    assert!(exists<Royalty>(addr), error::not_found(EROYALTY_DOES_NOT_EXIST));
+    move_from<Royalty>(addr);
+}
+
+ + + +
+ + + +## Function `get` + + + +
public fun get<T: key>(maybe_royalty: object::Object<T>): option::Option<royalty::Royalty>
+
+ + + +
+Implementation + + +
public fun get<T: key>(maybe_royalty: Object<T>): Option<Royalty> acquires Royalty {
+    let obj_addr = object::object_address(&maybe_royalty);
+    if (exists<Royalty>(obj_addr)) {
+        option::some(*borrow_global<Royalty>(obj_addr))
+    } else {
+        option::none()
+    }
+}
+
+ + + +
+ + + +## Function `denominator` + + + +
public fun denominator(royalty: &royalty::Royalty): u64
+
+ + + +
+Implementation + + +
public fun denominator(royalty: &Royalty): u64 {
+    royalty.denominator
+}
+
+ + + +
+ + + +## Function `numerator` + + + +
public fun numerator(royalty: &royalty::Royalty): u64
+
+ + + +
+Implementation + + +
public fun numerator(royalty: &Royalty): u64 {
+    royalty.numerator
+}
+
+ + + +
+ + + +## Function `payee_address` + + + +
public fun payee_address(royalty: &royalty::Royalty): address
+
+ + + +
+Implementation + + +
public fun payee_address(royalty: &Royalty): address {
+    royalty.payee_address
+}
+
+ + + +
+ + +[move-book]: https://move-language.github.io/move/introduction.html diff --git a/aptos-move/framework/aptos-token-objects/doc/token.md b/aptos-move/framework/aptos-token-objects/doc/token.md new file mode 100644 index 0000000000000..cc3cbdd3a8736 --- /dev/null +++ b/aptos-move/framework/aptos-token-objects/doc/token.md @@ -0,0 +1,799 @@ + + + +# Module `0x4::token` + +This defines an object-based Token. The key differentiating features from the Aptos standard +token are: +* Decouple token ownership from token data. +* Explicit data model for token metadata via adjacent resources +* Extensible framework for tokens + +TODO: +* Update Object to be a viable input as a transaction arg and then update all readers as view. + + +- [Resource `Token`](#0x4_token_Token) +- [Struct `BurnRef`](#0x4_token_BurnRef) +- [Struct `MutationEvent`](#0x4_token_MutationEvent) +- [Struct `MutatorRef`](#0x4_token_MutatorRef) +- [Constants](#@Constants_0) +- [Function `create`](#0x4_token_create) +- [Function `create_token_address`](#0x4_token_create_token_address) +- [Function `create_token_seed`](#0x4_token_create_token_seed) +- [Function `generate_mutator_ref`](#0x4_token_generate_mutator_ref) +- [Function `generate_burn_ref`](#0x4_token_generate_burn_ref) +- [Function `address_from_burn_ref`](#0x4_token_address_from_burn_ref) +- [Function `creator`](#0x4_token_creator) +- [Function `collection`](#0x4_token_collection) +- [Function `collection_object`](#0x4_token_collection_object) +- [Function `creation_name`](#0x4_token_creation_name) +- [Function `description`](#0x4_token_description) +- [Function `name`](#0x4_token_name) +- [Function `uri`](#0x4_token_uri) +- [Function `royalty`](#0x4_token_royalty) +- [Function `burn`](#0x4_token_burn) +- [Function `set_description`](#0x4_token_set_description) +- [Function `set_name`](#0x4_token_set_name) +- [Function `set_uri`](#0x4_token_set_uri) + + +
use 0x1::error;
+use 0x1::event;
+use 0x1::object;
+use 0x1::option;
+use 0x1::signer;
+use 0x1::string;
+use 0x1::vector;
+use 0x4::collection;
+use 0x4::royalty;
+
+ + + + + +## Resource `Token` + +Represents the common fields to all tokens. + + +
struct Token has key
+
+ + + +
+Fields + + +
+
+collection: object::Object<collection::Collection> +
+
+ The collection from which this token resides. +
+
+collection_id: u64 +
+
+ Unique identifier within the collection, optional, 0 means unassigned +
+
+description: string::String +
+
+ A brief description of the token. +
+
+name: string::String +
+
+ The name of the token, which should be unique within the collection; the length of name + should be smaller than 128, characters, eg: "Aptos Animal #1234" +
+
+creation_name: option::Option<string::String> +
+
+ The creation name of the token. Since tokens are created with the name as part of the + object id generation. +
+
+uri: string::String +
+
+ The Uniform Resource Identifier (uri) pointing to the JSON file stored in off-chain + storage; the URL length will likely need a maximum any suggestions? +
+
+mutation_events: event::EventHandle<token::MutationEvent> +
+
+ Emitted upon any mutation of the token. +
+
+ + +
+ + + +## Struct `BurnRef` + +This enables burning an NFT, if possible, it will also delete the object. Note, the data +in inner and self occupies 32-bytes each, rather than have both, this data structure makes +a small optimization to support either and take a fixed amount of 34-bytes. + + +
struct BurnRef has drop, store
+
+ + + +
+Fields + + +
+
+inner: option::Option<object::DeleteRef> +
+
+ +
+
+self: option::Option<address> +
+
+ +
+
+ + +
+ + + +## Struct `MutationEvent` + +Contains the mutated fields name. This makes the life of indexers easier, so that they can +directly understand the behavior in a writeset. + + +
struct MutationEvent has drop, store
+
+ + + +
+Fields + + +
+
+mutated_field_name: string::String +
+
+ +
+
+ + +
+ + + +## Struct `MutatorRef` + +This enables mutating descritpion and URI by higher level services. + + +
struct MutatorRef has drop, store
+
+ + + +
+Fields + + +
+
+self: address +
+
+ +
+
+ + +
+ + + +## Constants + + + + +Attempted to mutate an immutable field + + +
const EFIELD_NOT_MUTABLE: u64 = 3;
+
+ + + + + +The provided signer is not the creator + + +
const ENOT_CREATOR: u64 = 2;
+
+ + + + + + + +
const ETOKEN_DOES_NOT_EXIST: u64 = 1;
+
+ + + + + +## Function `create` + +Creates a new token object and returns the ConstructorRef for additional specialization. + + +
public fun create(creator: &signer, collection_name: string::String, description: string::String, name: string::String, royalty: option::Option<royalty::Royalty>, uri: string::String): object::ConstructorRef
+
+ + + +
+Implementation + + +
public fun create(
+    creator: &signer,
+    collection_name: String,
+    description: String,
+    name: String,
+    royalty: Option<Royalty>,
+    uri: String,
+): ConstructorRef {
+    let creator_address = signer::address_of(creator);
+    let seed = create_token_seed(&collection_name, &name);
+
+    let collection_addr = collection::create_collection_address(&creator_address, &collection_name);
+    let collection = object::address_to_object<Collection>(collection_addr);
+    let id = collection::increment_supply(&collection);
+
+    let constructor_ref = object::create_named_object(creator, seed);
+    let object_signer = object::generate_signer(&constructor_ref);
+
+    let token = Token {
+        collection,
+        collection_id: option::get_with_default(&mut id, 0),
+        description,
+        name,
+        creation_name: option::none(),
+        uri,
+        mutation_events: object::new_event_handle(&object_signer),
+    };
+    move_to(&object_signer, token);
+
+    if (option::is_some(&royalty)) {
+        royalty::init(&constructor_ref, option::extract(&mut royalty))
+    };
+    constructor_ref
+}
+
+ + + +
+ + + +## Function `create_token_address` + +Generates the collections address based upon the creators address and the collection's name + + +
public fun create_token_address(creator: &address, collection: &string::String, name: &string::String): address
+
+ + + +
+Implementation + + +
public fun create_token_address(creator: &address, collection: &String, name: &String): address {
+    object::create_object_address(creator, create_token_seed(collection, name))
+}
+
+ + + +
+ + + +## Function `create_token_seed` + +Named objects are derived from a seed, the collection's seed is its name. + + +
public fun create_token_seed(collection: &string::String, name: &string::String): vector<u8>
+
+ + + +
+Implementation + + +
public fun create_token_seed(collection: &String, name: &String): vector<u8> {
+    let seed = *string::bytes(collection);
+    vector::append(&mut seed, b"::");
+    vector::append(&mut seed, *string::bytes(name));
+    seed
+}
+
+ + + +
+ + + +## Function `generate_mutator_ref` + +Creates a MutatorRef, which gates the ability to mutate any fields that support mutation. + + +
public fun generate_mutator_ref(ref: &object::ConstructorRef): token::MutatorRef
+
+ + + +
+Implementation + + +
public fun generate_mutator_ref(ref: &ConstructorRef): MutatorRef {
+    let object = object::object_from_constructor_ref<Token>(ref);
+    MutatorRef { self: object::object_address(&object) }
+}
+
+ + + +
+ + + +## Function `generate_burn_ref` + +Creates a BurnRef, which gates the ability to burn the given token. + + +
public fun generate_burn_ref(ref: &object::ConstructorRef): token::BurnRef
+
+ + + +
+Implementation + + +
public fun generate_burn_ref(ref: &ConstructorRef): BurnRef {
+    let (inner, self) = if (object::can_generate_delete_ref(ref)) {
+        let delete_ref = object::generate_delete_ref(ref);
+        (option::some(delete_ref), option::none())
+    } else {
+        let addr = object::address_from_constructor_ref(ref);
+        (option::none(), option::some(addr))
+    };
+    BurnRef { self, inner }
+}
+
+ + + +
+ + + +## Function `address_from_burn_ref` + +Extracts the tokens address from a BurnRef. + + +
public fun address_from_burn_ref(ref: &token::BurnRef): address
+
+ + + +
+Implementation + + +
public fun address_from_burn_ref(ref: &BurnRef): address {
+    if (option::is_some(&ref.inner)) {
+        object::address_from_delete_ref(option::borrow(&ref.inner))
+    } else {
+        *option::borrow(&ref.self)
+    }
+}
+
+ + + +
+ + + +## Function `creator` + + + +
public fun creator<T: key>(token: object::Object<T>): address
+
+ + + +
+Implementation + + +
public fun creator<T: key>(token: Object<T>): address acquires Token {
+    collection::creator(borrow(&token).collection)
+}
+
+ + + +
+ + + +## Function `collection` + + + +
public fun collection<T: key>(token: object::Object<T>): string::String
+
+ + + +
+Implementation + + +
public fun collection<T: key>(token: Object<T>): String acquires Token {
+    collection::name(borrow(&token).collection)
+}
+
+ + + +
+ + + +## Function `collection_object` + + + +
public fun collection_object<T: key>(token: object::Object<T>): object::Object<collection::Collection>
+
+ + + +
+Implementation + + +
public fun collection_object<T: key>(token: Object<T>): Object<Collection> acquires Token {
+    borrow(&token).collection
+}
+
+ + + +
+ + + +## Function `creation_name` + + + +
public fun creation_name<T: key>(token: object::Object<T>): string::String
+
+ + + +
+Implementation + + +
public fun creation_name<T: key>(token: Object<T>): String acquires Token {
+    let token = borrow(&token);
+    if (option::is_some(&token.creation_name)) {
+        *option::borrow(&token.creation_name)
+    } else {
+        token.name
+    }
+}
+
+ + + +
+ + + +## Function `description` + + + +
public fun description<T: key>(token: object::Object<T>): string::String
+
+ + + +
+Implementation + + +
public fun description<T: key>(token: Object<T>): String acquires Token {
+    borrow(&token).description
+}
+
+ + + +
+ + + +## Function `name` + + + +
public fun name<T: key>(token: object::Object<T>): string::String
+
+ + + +
+Implementation + + +
public fun name<T: key>(token: Object<T>): String acquires Token {
+    borrow(&token).name
+}
+
+ + + +
+ + + +## Function `uri` + + + +
public fun uri<T: key>(token: object::Object<T>): string::String
+
+ + + +
+Implementation + + +
public fun uri<T: key>(token: Object<T>): String acquires Token {
+    borrow(&token).uri
+}
+
+ + + +
+ + + +## Function `royalty` + + + +
public fun royalty<T: key>(token: object::Object<T>): option::Option<royalty::Royalty>
+
+ + + +
+Implementation + + +
public fun royalty<T: key>(token: Object<T>): Option<Royalty> acquires Token {
+    borrow(&token);
+    let royalty = royalty::get(token);
+    if (option::is_some(&royalty)) {
+        royalty
+    } else {
+        let creator = creator(token);
+        let collection_name = collection(token);
+        let collection_address = collection::create_collection_address(&creator, &collection_name);
+        let collection = object::address_to_object<collection::Collection>(collection_address);
+        royalty::get(collection)
+    }
+}
+
+ + + +
+ + + +## Function `burn` + + + +
public fun burn(burn_ref: token::BurnRef)
+
+ + + +
+Implementation + + +
public fun burn(burn_ref: BurnRef) acquires Token {
+    let addr = if (option::is_some(&burn_ref.inner)) {
+        let delete_ref = option::extract(&mut burn_ref.inner);
+        let addr = object::address_from_delete_ref(&delete_ref);
+        object::delete(delete_ref);
+        addr
+    } else {
+        option::extract(&mut burn_ref.self)
+    };
+
+    if (royalty::exists_at(addr)) {
+        royalty::delete(addr)
+    };
+
+    let Token {
+        collection,
+        collection_id: _,
+        description: _,
+        name: _,
+        creation_name: _,
+        uri: _,
+        mutation_events,
+    } = move_from<Token>(addr);
+
+    event::destroy_handle(mutation_events);
+    collection::decrement_supply(&collection);
+}
+
+ + + +
+ + + +## Function `set_description` + + + +
public fun set_description(mutator_ref: &token::MutatorRef, description: string::String)
+
+ + + +
+Implementation + + +
public fun set_description(
+    mutator_ref: &MutatorRef,
+    description: String,
+) acquires Token {
+    let token = borrow_mut(mutator_ref);
+    token.description = description;
+    event::emit_event(
+        &mut token.mutation_events,
+        MutationEvent { mutated_field_name: string::utf8(b"description") },
+    );
+}
+
+ + + +
+ + + +## Function `set_name` + + + +
public fun set_name(mutator_ref: &token::MutatorRef, name: string::String)
+
+ + + +
+Implementation + + +
public fun set_name(
+    mutator_ref: &MutatorRef,
+    name: String,
+) acquires Token {
+    let token = borrow_mut(mutator_ref);
+    if (option::is_none(&token.creation_name)) {
+        option::fill(&mut token.creation_name, token.name)
+    };
+    token.name = name;
+    event::emit_event(
+        &mut token.mutation_events,
+        MutationEvent { mutated_field_name: string::utf8(b"name") },
+    );
+}
+
+ + + +
+ + + +## Function `set_uri` + + + +
public fun set_uri(mutator_ref: &token::MutatorRef, uri: string::String)
+
+ + + +
+Implementation + + +
public fun set_uri(
+    mutator_ref: &MutatorRef,
+    uri: String,
+) acquires Token {
+    let token = borrow_mut(mutator_ref);
+    token.uri = uri;
+    event::emit_event(
+        &mut token.mutation_events,
+        MutationEvent { mutated_field_name: string::utf8(b"uri") },
+    );
+}
+
+ + + +
+ + +[move-book]: https://move-language.github.io/move/introduction.html diff --git a/aptos-move/framework/aptos-token-objects/doc_template/overview.md b/aptos-move/framework/aptos-token-objects/doc_template/overview.md new file mode 100644 index 0000000000000..006db85f6117a --- /dev/null +++ b/aptos-move/framework/aptos-token-objects/doc_template/overview.md @@ -0,0 +1,7 @@ +# Aptos Token Framework + +This is the reference documentation of the Aptos Token Objects framework. + +## Index + +> {{move-index}} diff --git a/aptos-move/framework/aptos-token-objects/doc_template/references.md b/aptos-move/framework/aptos-token-objects/doc_template/references.md new file mode 100644 index 0000000000000..147a67c84546c --- /dev/null +++ b/aptos-move/framework/aptos-token-objects/doc_template/references.md @@ -0,0 +1 @@ +[move-book]: https://move-language.github.io/move/introduction.html diff --git a/aptos-move/move-examples/token_objects/sources/aptos_token.move b/aptos-move/framework/aptos-token-objects/sources/aptos_token.move similarity index 99% rename from aptos-move/move-examples/token_objects/sources/aptos_token.move rename to aptos-move/framework/aptos-token-objects/sources/aptos_token.move index 09af3360cbc2f..5c70cc0c27504 100644 --- a/aptos-move/move-examples/token_objects/sources/aptos_token.move +++ b/aptos-move/framework/aptos-token-objects/sources/aptos_token.move @@ -6,7 +6,7 @@ /// * Creator-based freezing of tokens /// * Standard object-based transfer and events /// * Metadata property type -module token_objects::aptos_token { +module aptos_token_objects::aptos_token { use std::error; use std::option::{Self, Option}; use std::string::String; @@ -14,10 +14,10 @@ module token_objects::aptos_token { use aptos_framework::object::{Self, ConstructorRef, Object}; - use token_objects::collection; - use token_objects::property_map; - use token_objects::royalty; - use token_objects::token; + use aptos_token_objects::collection; + use aptos_token_objects::property_map; + use aptos_token_objects::royalty; + use aptos_token_objects::token; // The token does not exist const ETOKEN_DOES_NOT_EXIST: u64 = 1; diff --git a/aptos-move/move-examples/token_objects/sources/collection.move b/aptos-move/framework/aptos-token-objects/sources/collection.move similarity index 99% rename from aptos-move/move-examples/token_objects/sources/collection.move rename to aptos-move/framework/aptos-token-objects/sources/collection.move index 2303659b6e86f..b37d0a9b87f92 100644 --- a/aptos-move/move-examples/token_objects/sources/collection.move +++ b/aptos-move/framework/aptos-token-objects/sources/collection.move @@ -20,7 +20,7 @@ /// * Consider supporting changing the aspects of supply with the MutatorRef. /// * Add aggregator support when added to framework /// * Update Object to be viable input as a transaction arg and then update all readers as view. -module token_objects::collection { +module aptos_token_objects::collection { use std::error; use std::option::{Self, Option}; use std::signer; @@ -29,9 +29,9 @@ module token_objects::collection { use aptos_framework::event; use aptos_framework::object::{Self, ConstructorRef, Object}; - use token_objects::royalty::{Self, Royalty}; + use aptos_token_objects::royalty::{Self, Royalty}; - friend token_objects::token; + friend aptos_token_objects::token; /// The collections supply is at its maximum amount const EEXCEEDS_MAX_SUPPLY: u64 = 1; diff --git a/aptos-move/move-examples/token_objects/sources/property_map.move b/aptos-move/framework/aptos-token-objects/sources/property_map.move similarity index 99% rename from aptos-move/move-examples/token_objects/sources/property_map.move rename to aptos-move/framework/aptos-token-objects/sources/property_map.move index e5d34812f9a94..0435efa183608 100644 --- a/aptos-move/move-examples/token_objects/sources/property_map.move +++ b/aptos-move/framework/aptos-token-objects/sources/property_map.move @@ -1,7 +1,7 @@ /// PropertyMap provides generic metadata support for AptosToken. It is a specialization of /// SimpleMap that enforces strict typing with minimal storage use by using constant u64 to /// represent types and storing values in bcs format. -module token_objects::property_map { +module aptos_token_objects::property_map { use std::bcs; use std::vector; use std::error; diff --git a/aptos-move/move-examples/token_objects/sources/royalty.move b/aptos-move/framework/aptos-token-objects/sources/royalty.move similarity index 98% rename from aptos-move/move-examples/token_objects/sources/royalty.move rename to aptos-move/framework/aptos-token-objects/sources/royalty.move index 5d1c47b0c4273..82a53c1a13f12 100644 --- a/aptos-move/move-examples/token_objects/sources/royalty.move +++ b/aptos-move/framework/aptos-token-objects/sources/royalty.move @@ -1,13 +1,13 @@ /// This defines an object-based Royalty. The royalty can be applied to either a collection or a /// token. Applications should read the royalty from the token, as it will read the appropriate /// royalty. -module token_objects::royalty { +module aptos_token_objects::royalty { use std::error; use std::option::{Self, Option}; use aptos_framework::object::{Self, ConstructorRef, ExtendRef, Object}; - friend token_objects::token; + friend aptos_token_objects::token; // Enforce that the royalty is between 0 and 1 const EROYALTY_EXCEEDS_MAXIMUM: u64 = 1; diff --git a/aptos-move/move-examples/token_objects/sources/token.move b/aptos-move/framework/aptos-token-objects/sources/token.move similarity index 98% rename from aptos-move/move-examples/token_objects/sources/token.move rename to aptos-move/framework/aptos-token-objects/sources/token.move index 98398a318b026..31b0f321d0b9c 100644 --- a/aptos-move/move-examples/token_objects/sources/token.move +++ b/aptos-move/framework/aptos-token-objects/sources/token.move @@ -6,7 +6,7 @@ /// /// TODO: /// * Update Object to be a viable input as a transaction arg and then update all readers as view. -module token_objects::token { +module aptos_token_objects::token { use std::error; use std::option::{Self, Option}; use std::string::{Self, String}; @@ -16,8 +16,8 @@ module token_objects::token { use aptos_framework::event; use aptos_framework::object::{Self, ConstructorRef, Object}; - use token_objects::collection::{Self, Collection}; - use token_objects::royalty::{Self, Royalty}; + use aptos_token_objects::collection::{Self, Collection}; + use aptos_token_objects::royalty::{Self, Royalty}; // The token does not exist const ETOKEN_DOES_NOT_EXIST: u64 = 1; @@ -359,7 +359,7 @@ module token_objects::token { } #[test(creator = @0x123)] - #[expected_failure(abort_code = 0x20001, location = token_objects::collection)] + #[expected_failure(abort_code = 0x20001, location = aptos_token_objects::collection)] fun test_too_many_tokens(creator: &signer) { let collection_name = string::utf8(b"collection name"); let token_name = string::utf8(b"token name"); diff --git a/aptos-move/framework/cached-packages/src/aptos_token_objects_sdk_builder.rs b/aptos-move/framework/cached-packages/src/aptos_token_objects_sdk_builder.rs new file mode 100644 index 0000000000000..6de4f579e6676 --- /dev/null +++ b/aptos-move/framework/cached-packages/src/aptos_token_objects_sdk_builder.rs @@ -0,0 +1,664 @@ + +// Copyright © Aptos Foundation +// SPDX-License-Identifier: Apache-2.0 + +// This file was generated. Do not modify! +// +// To update this code, run: `cargo run --release -p framework`. + +// Conversion library between a structured representation of a Move script call (`ScriptCall`) and the +// standard BCS-compatible representation used in Aptos transactions (`Script`). +// +// This code was generated by compiling known Script interfaces ("ABIs") with the tool `aptos-sdk-builder`. + +#![allow(dead_code)] +#![allow(unused_imports)] +use aptos_types::account_address::{AccountAddress}; +use aptos_types::transaction::{TransactionPayload, EntryFunction}; +use move_core_types::{ident_str}; +use move_core_types::language_storage::{ModuleId, TypeTag}; + +type Bytes = Vec; + + +/// Structured representation of a call into a known Move entry function. +/// ```ignore +/// impl EntryFunctionCall { +/// pub fn encode(self) -> TransactionPayload { .. } +/// pub fn decode(&TransactionPayload) -> Option { .. } +/// } +/// ``` +#[derive(Clone, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "fuzzing", derive(proptest_derive::Arbitrary))] +#[cfg_attr(feature = "fuzzing", proptest(no_params))] +pub enum EntryFunctionCall { + + + AptosTokenAddPropertyCall { + collection: Vec, + name: Vec, + key: Vec, + type: Vec, + value: Vec, + }, + + + AptosTokenBurnCall { + collection: Vec, + name: Vec, + }, + + /// Create a new collection + AptosTokenCreateCollection { + description: Vec, + max_supply: u64, + name: Vec, + uri: Vec, + mutable_description: bool, + mutable_royalty: bool, + mutable_uri: bool, + mutable_token_description: bool, + mutable_token_name: bool, + mutable_token_properties: bool, + mutable_token_uri: bool, + tokens_burnable_by_creator: bool, + tokens_freezable_by_creator: bool, + royalty_numerator: u64, + royalty_denominator: u64, + }, + + + AptosTokenFreezeTransferCall { + collection: Vec, + name: Vec, + }, + + /// With an existing collection, directly mint a viable token into the creators account. + AptosTokenMint { + collection: Vec, + description: Vec, + name: Vec, + uri: Vec, + property_keys: Vec>, + property_types: Vec>, + property_values: Vec>, + }, + + /// With an existing collection, directly mint a soul bound token into the recipient's account. + AptosTokenMintSoulBound { + collection: Vec, + description: Vec, + name: Vec, + uri: Vec, + property_keys: Vec>, + property_types: Vec>, + property_values: Vec>, + soul_bound_to: AccountAddress, + }, + + + AptosTokenRemovePropertyCall { + collection: Vec, + name: Vec, + key: Vec, + }, + + + AptosTokenSetCollectionDescriptionCall { + collection: Vec, + description: Vec, + }, + + + AptosTokenSetCollectionRoyaltiesCall { + collection: Vec, + royalty_numerator: u64, + royalty_denominator: u64, + payee_address: AccountAddress, + }, + + + AptosTokenSetCollectionUriCall { + collection: Vec, + uri: Vec, + }, + + + AptosTokenSetDescriptionCall { + collection: Vec, + name: Vec, + description: Vec, + }, + + + AptosTokenSetNameCall { + collection: Vec, + original_name: Vec, + new_name: Vec, + }, + + + AptosTokenSetUriCall { + collection: Vec, + name: Vec, + uri: Vec, + }, + + + AptosTokenUnfreezeTransferCall { + collection: Vec, + name: Vec, + }, + + + AptosTokenUpdatePropertyCall { + collection: Vec, + name: Vec, + key: Vec, + type: Vec, + value: Vec, + }, + + /// Entry function for creating a collection + CollectionCreateCollection { + description: Vec, + name: Vec, + uri: Vec, + max_supply: u64, + enable_royalty: bool, + royalty_numerator: u64, + royalty_denominator: u64, + royalty_payee_address: AccountAddress, + }, +} + + +impl EntryFunctionCall { + + /// Build an Aptos `TransactionPayload` from a structured object `EntryFunctionCall`. + pub fn encode(self) -> TransactionPayload { + use EntryFunctionCall::*; + match self { + AptosTokenAddPropertyCall{collection, name, key, type, value} => aptos_token_add_property_call(collection, name, key, type, value), + AptosTokenBurnCall{collection, name} => aptos_token_burn_call(collection, name), + AptosTokenCreateCollection{description, max_supply, name, uri, mutable_description, mutable_royalty, mutable_uri, mutable_token_description, mutable_token_name, mutable_token_properties, mutable_token_uri, tokens_burnable_by_creator, tokens_freezable_by_creator, royalty_numerator, royalty_denominator} => aptos_token_create_collection(description, max_supply, name, uri, mutable_description, mutable_royalty, mutable_uri, mutable_token_description, mutable_token_name, mutable_token_properties, mutable_token_uri, tokens_burnable_by_creator, tokens_freezable_by_creator, royalty_numerator, royalty_denominator), + AptosTokenFreezeTransferCall{collection, name} => aptos_token_freeze_transfer_call(collection, name), + AptosTokenMint{collection, description, name, uri, property_keys, property_types, property_values} => aptos_token_mint(collection, description, name, uri, property_keys, property_types, property_values), + AptosTokenMintSoulBound{collection, description, name, uri, property_keys, property_types, property_values, soul_bound_to} => aptos_token_mint_soul_bound(collection, description, name, uri, property_keys, property_types, property_values, soul_bound_to), + AptosTokenRemovePropertyCall{collection, name, key} => aptos_token_remove_property_call(collection, name, key), + AptosTokenSetCollectionDescriptionCall{collection, description} => aptos_token_set_collection_description_call(collection, description), + AptosTokenSetCollectionRoyaltiesCall{collection, royalty_numerator, royalty_denominator, payee_address} => aptos_token_set_collection_royalties_call(collection, royalty_numerator, royalty_denominator, payee_address), + AptosTokenSetCollectionUriCall{collection, uri} => aptos_token_set_collection_uri_call(collection, uri), + AptosTokenSetDescriptionCall{collection, name, description} => aptos_token_set_description_call(collection, name, description), + AptosTokenSetNameCall{collection, original_name, new_name} => aptos_token_set_name_call(collection, original_name, new_name), + AptosTokenSetUriCall{collection, name, uri} => aptos_token_set_uri_call(collection, name, uri), + AptosTokenUnfreezeTransferCall{collection, name} => aptos_token_unfreeze_transfer_call(collection, name), + AptosTokenUpdatePropertyCall{collection, name, key, type, value} => aptos_token_update_property_call(collection, name, key, type, value), + CollectionCreateCollection{description, name, uri, max_supply, enable_royalty, royalty_numerator, royalty_denominator, royalty_payee_address} => collection_create_collection(description, name, uri, max_supply, enable_royalty, royalty_numerator, royalty_denominator, royalty_payee_address), + } + } + + + /// Try to recognize an Aptos `TransactionPayload` and convert it into a structured object `EntryFunctionCall`. + pub fn decode(payload: &TransactionPayload) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + match SCRIPT_FUNCTION_DECODER_MAP.get(&format!("{}_{}", script.module().name(), script.function())) { + Some(decoder) => decoder(payload), + None => None, + } + } else { + None + } + } + +} + + +pub fn aptos_token_add_property_call(collection: Vec, name: Vec, key: Vec, type: Vec, value: Vec) -> 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, 4]), + ident_str!("aptos_token").to_owned(), + ), + ident_str!("add_property_call").to_owned(), + vec![], + vec![bcs::to_bytes(&collection).unwrap(), bcs::to_bytes(&name).unwrap(), bcs::to_bytes(&key).unwrap(), bcs::to_bytes(&type).unwrap(), bcs::to_bytes(&value).unwrap()], + )) +} + + +pub fn aptos_token_burn_call(collection: Vec, name: Vec) -> 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, 4]), + ident_str!("aptos_token").to_owned(), + ), + ident_str!("burn_call").to_owned(), + vec![], + vec![bcs::to_bytes(&collection).unwrap(), bcs::to_bytes(&name).unwrap()], + )) +} + +/// Create a new collection +pub fn aptos_token_create_collection(description: Vec, max_supply: u64, name: Vec, uri: Vec, mutable_description: bool, mutable_royalty: bool, mutable_uri: bool, mutable_token_description: bool, mutable_token_name: bool, mutable_token_properties: bool, mutable_token_uri: bool, tokens_burnable_by_creator: bool, tokens_freezable_by_creator: bool, royalty_numerator: u64, royalty_denominator: u64) -> 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, 4]), + ident_str!("aptos_token").to_owned(), + ), + ident_str!("create_collection").to_owned(), + vec![], + vec![bcs::to_bytes(&description).unwrap(), bcs::to_bytes(&max_supply).unwrap(), bcs::to_bytes(&name).unwrap(), bcs::to_bytes(&uri).unwrap(), bcs::to_bytes(&mutable_description).unwrap(), bcs::to_bytes(&mutable_royalty).unwrap(), bcs::to_bytes(&mutable_uri).unwrap(), bcs::to_bytes(&mutable_token_description).unwrap(), bcs::to_bytes(&mutable_token_name).unwrap(), bcs::to_bytes(&mutable_token_properties).unwrap(), bcs::to_bytes(&mutable_token_uri).unwrap(), bcs::to_bytes(&tokens_burnable_by_creator).unwrap(), bcs::to_bytes(&tokens_freezable_by_creator).unwrap(), bcs::to_bytes(&royalty_numerator).unwrap(), bcs::to_bytes(&royalty_denominator).unwrap()], + )) +} + + +pub fn aptos_token_freeze_transfer_call(collection: Vec, name: Vec) -> 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, 4]), + ident_str!("aptos_token").to_owned(), + ), + ident_str!("freeze_transfer_call").to_owned(), + vec![], + vec![bcs::to_bytes(&collection).unwrap(), bcs::to_bytes(&name).unwrap()], + )) +} + +/// With an existing collection, directly mint a viable token into the creators account. +pub fn aptos_token_mint(collection: Vec, description: Vec, name: Vec, uri: Vec, property_keys: Vec>, property_types: Vec>, property_values: Vec>) -> 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, 4]), + ident_str!("aptos_token").to_owned(), + ), + ident_str!("mint").to_owned(), + vec![], + vec![bcs::to_bytes(&collection).unwrap(), bcs::to_bytes(&description).unwrap(), bcs::to_bytes(&name).unwrap(), bcs::to_bytes(&uri).unwrap(), bcs::to_bytes(&property_keys).unwrap(), bcs::to_bytes(&property_types).unwrap(), bcs::to_bytes(&property_values).unwrap()], + )) +} + +/// With an existing collection, directly mint a soul bound token into the recipient's account. +pub fn aptos_token_mint_soul_bound(collection: Vec, description: Vec, name: Vec, uri: Vec, property_keys: Vec>, property_types: Vec>, property_values: Vec>, soul_bound_to: AccountAddress) -> 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, 4]), + ident_str!("aptos_token").to_owned(), + ), + ident_str!("mint_soul_bound").to_owned(), + vec![], + vec![bcs::to_bytes(&collection).unwrap(), bcs::to_bytes(&description).unwrap(), bcs::to_bytes(&name).unwrap(), bcs::to_bytes(&uri).unwrap(), bcs::to_bytes(&property_keys).unwrap(), bcs::to_bytes(&property_types).unwrap(), bcs::to_bytes(&property_values).unwrap(), bcs::to_bytes(&soul_bound_to).unwrap()], + )) +} + + +pub fn aptos_token_remove_property_call(collection: Vec, name: Vec, key: Vec) -> 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, 4]), + ident_str!("aptos_token").to_owned(), + ), + ident_str!("remove_property_call").to_owned(), + vec![], + vec![bcs::to_bytes(&collection).unwrap(), bcs::to_bytes(&name).unwrap(), bcs::to_bytes(&key).unwrap()], + )) +} + + +pub fn aptos_token_set_collection_description_call(collection: Vec, description: Vec) -> 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, 4]), + ident_str!("aptos_token").to_owned(), + ), + ident_str!("set_collection_description_call").to_owned(), + vec![], + vec![bcs::to_bytes(&collection).unwrap(), bcs::to_bytes(&description).unwrap()], + )) +} + + +pub fn aptos_token_set_collection_royalties_call(collection: Vec, royalty_numerator: u64, royalty_denominator: u64, payee_address: AccountAddress) -> 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, 4]), + ident_str!("aptos_token").to_owned(), + ), + ident_str!("set_collection_royalties_call").to_owned(), + vec![], + vec![bcs::to_bytes(&collection).unwrap(), bcs::to_bytes(&royalty_numerator).unwrap(), bcs::to_bytes(&royalty_denominator).unwrap(), bcs::to_bytes(&payee_address).unwrap()], + )) +} + + +pub fn aptos_token_set_collection_uri_call(collection: Vec, uri: Vec) -> 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, 4]), + ident_str!("aptos_token").to_owned(), + ), + ident_str!("set_collection_uri_call").to_owned(), + vec![], + vec![bcs::to_bytes(&collection).unwrap(), bcs::to_bytes(&uri).unwrap()], + )) +} + + +pub fn aptos_token_set_description_call(collection: Vec, name: Vec, description: Vec) -> 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, 4]), + ident_str!("aptos_token").to_owned(), + ), + ident_str!("set_description_call").to_owned(), + vec![], + vec![bcs::to_bytes(&collection).unwrap(), bcs::to_bytes(&name).unwrap(), bcs::to_bytes(&description).unwrap()], + )) +} + + +pub fn aptos_token_set_name_call(collection: Vec, original_name: Vec, new_name: Vec) -> 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, 4]), + ident_str!("aptos_token").to_owned(), + ), + ident_str!("set_name_call").to_owned(), + vec![], + vec![bcs::to_bytes(&collection).unwrap(), bcs::to_bytes(&original_name).unwrap(), bcs::to_bytes(&new_name).unwrap()], + )) +} + + +pub fn aptos_token_set_uri_call(collection: Vec, name: Vec, uri: Vec) -> 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, 4]), + ident_str!("aptos_token").to_owned(), + ), + ident_str!("set_uri_call").to_owned(), + vec![], + vec![bcs::to_bytes(&collection).unwrap(), bcs::to_bytes(&name).unwrap(), bcs::to_bytes(&uri).unwrap()], + )) +} + + +pub fn aptos_token_unfreeze_transfer_call(collection: Vec, name: Vec) -> 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, 4]), + ident_str!("aptos_token").to_owned(), + ), + ident_str!("unfreeze_transfer_call").to_owned(), + vec![], + vec![bcs::to_bytes(&collection).unwrap(), bcs::to_bytes(&name).unwrap()], + )) +} + + +pub fn aptos_token_update_property_call(collection: Vec, name: Vec, key: Vec, type: Vec, value: Vec) -> 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, 4]), + ident_str!("aptos_token").to_owned(), + ), + ident_str!("update_property_call").to_owned(), + vec![], + vec![bcs::to_bytes(&collection).unwrap(), bcs::to_bytes(&name).unwrap(), bcs::to_bytes(&key).unwrap(), bcs::to_bytes(&type).unwrap(), bcs::to_bytes(&value).unwrap()], + )) +} + +/// Entry function for creating a collection +pub fn collection_create_collection(description: Vec, name: Vec, uri: Vec, max_supply: u64, enable_royalty: bool, royalty_numerator: u64, royalty_denominator: u64, royalty_payee_address: AccountAddress) -> 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, 4]), + ident_str!("collection").to_owned(), + ), + ident_str!("create_collection").to_owned(), + vec![], + vec![bcs::to_bytes(&description).unwrap(), bcs::to_bytes(&name).unwrap(), bcs::to_bytes(&uri).unwrap(), bcs::to_bytes(&max_supply).unwrap(), bcs::to_bytes(&enable_royalty).unwrap(), bcs::to_bytes(&royalty_numerator).unwrap(), bcs::to_bytes(&royalty_denominator).unwrap(), bcs::to_bytes(&royalty_payee_address).unwrap()], + )) +} +mod decoder { use super::*; +pub fn aptos_token_add_property_call(payload: &TransactionPayload) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::AptosTokenAddPropertyCall { + collection : bcs::from_bytes(script.args().get(0)?).ok()?, + name : bcs::from_bytes(script.args().get(1)?).ok()?, + key : bcs::from_bytes(script.args().get(2)?).ok()?, + type : bcs::from_bytes(script.args().get(3)?).ok()?, + value : bcs::from_bytes(script.args().get(4)?).ok()?, + }) + } else { + None + } +} + +pub fn aptos_token_burn_call(payload: &TransactionPayload) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::AptosTokenBurnCall { + collection : bcs::from_bytes(script.args().get(0)?).ok()?, + name : bcs::from_bytes(script.args().get(1)?).ok()?, + }) + } else { + None + } +} + +pub fn aptos_token_create_collection(payload: &TransactionPayload) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::AptosTokenCreateCollection { + description : bcs::from_bytes(script.args().get(0)?).ok()?, + max_supply : bcs::from_bytes(script.args().get(1)?).ok()?, + name : bcs::from_bytes(script.args().get(2)?).ok()?, + uri : bcs::from_bytes(script.args().get(3)?).ok()?, + mutable_description : bcs::from_bytes(script.args().get(4)?).ok()?, + mutable_royalty : bcs::from_bytes(script.args().get(5)?).ok()?, + mutable_uri : bcs::from_bytes(script.args().get(6)?).ok()?, + mutable_token_description : bcs::from_bytes(script.args().get(7)?).ok()?, + mutable_token_name : bcs::from_bytes(script.args().get(8)?).ok()?, + mutable_token_properties : bcs::from_bytes(script.args().get(9)?).ok()?, + mutable_token_uri : bcs::from_bytes(script.args().get(10)?).ok()?, + tokens_burnable_by_creator : bcs::from_bytes(script.args().get(11)?).ok()?, + tokens_freezable_by_creator : bcs::from_bytes(script.args().get(12)?).ok()?, + royalty_numerator : bcs::from_bytes(script.args().get(13)?).ok()?, + royalty_denominator : bcs::from_bytes(script.args().get(14)?).ok()?, + }) + } else { + None + } +} + +pub fn aptos_token_freeze_transfer_call(payload: &TransactionPayload) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::AptosTokenFreezeTransferCall { + collection : bcs::from_bytes(script.args().get(0)?).ok()?, + name : bcs::from_bytes(script.args().get(1)?).ok()?, + }) + } else { + None + } +} + +pub fn aptos_token_mint(payload: &TransactionPayload) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::AptosTokenMint { + collection : bcs::from_bytes(script.args().get(0)?).ok()?, + description : bcs::from_bytes(script.args().get(1)?).ok()?, + name : bcs::from_bytes(script.args().get(2)?).ok()?, + uri : bcs::from_bytes(script.args().get(3)?).ok()?, + property_keys : bcs::from_bytes(script.args().get(4)?).ok()?, + property_types : bcs::from_bytes(script.args().get(5)?).ok()?, + property_values : bcs::from_bytes(script.args().get(6)?).ok()?, + }) + } else { + None + } +} + +pub fn aptos_token_mint_soul_bound(payload: &TransactionPayload) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::AptosTokenMintSoulBound { + collection : bcs::from_bytes(script.args().get(0)?).ok()?, + description : bcs::from_bytes(script.args().get(1)?).ok()?, + name : bcs::from_bytes(script.args().get(2)?).ok()?, + uri : bcs::from_bytes(script.args().get(3)?).ok()?, + property_keys : bcs::from_bytes(script.args().get(4)?).ok()?, + property_types : bcs::from_bytes(script.args().get(5)?).ok()?, + property_values : bcs::from_bytes(script.args().get(6)?).ok()?, + soul_bound_to : bcs::from_bytes(script.args().get(7)?).ok()?, + }) + } else { + None + } +} + +pub fn aptos_token_remove_property_call(payload: &TransactionPayload) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::AptosTokenRemovePropertyCall { + collection : bcs::from_bytes(script.args().get(0)?).ok()?, + name : bcs::from_bytes(script.args().get(1)?).ok()?, + key : bcs::from_bytes(script.args().get(2)?).ok()?, + }) + } else { + None + } +} + +pub fn aptos_token_set_collection_description_call(payload: &TransactionPayload) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::AptosTokenSetCollectionDescriptionCall { + collection : bcs::from_bytes(script.args().get(0)?).ok()?, + description : bcs::from_bytes(script.args().get(1)?).ok()?, + }) + } else { + None + } +} + +pub fn aptos_token_set_collection_royalties_call(payload: &TransactionPayload) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::AptosTokenSetCollectionRoyaltiesCall { + collection : bcs::from_bytes(script.args().get(0)?).ok()?, + royalty_numerator : bcs::from_bytes(script.args().get(1)?).ok()?, + royalty_denominator : bcs::from_bytes(script.args().get(2)?).ok()?, + payee_address : bcs::from_bytes(script.args().get(3)?).ok()?, + }) + } else { + None + } +} + +pub fn aptos_token_set_collection_uri_call(payload: &TransactionPayload) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::AptosTokenSetCollectionUriCall { + collection : bcs::from_bytes(script.args().get(0)?).ok()?, + uri : bcs::from_bytes(script.args().get(1)?).ok()?, + }) + } else { + None + } +} + +pub fn aptos_token_set_description_call(payload: &TransactionPayload) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::AptosTokenSetDescriptionCall { + collection : bcs::from_bytes(script.args().get(0)?).ok()?, + name : bcs::from_bytes(script.args().get(1)?).ok()?, + description : bcs::from_bytes(script.args().get(2)?).ok()?, + }) + } else { + None + } +} + +pub fn aptos_token_set_name_call(payload: &TransactionPayload) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::AptosTokenSetNameCall { + collection : bcs::from_bytes(script.args().get(0)?).ok()?, + original_name : bcs::from_bytes(script.args().get(1)?).ok()?, + new_name : bcs::from_bytes(script.args().get(2)?).ok()?, + }) + } else { + None + } +} + +pub fn aptos_token_set_uri_call(payload: &TransactionPayload) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::AptosTokenSetUriCall { + collection : bcs::from_bytes(script.args().get(0)?).ok()?, + name : bcs::from_bytes(script.args().get(1)?).ok()?, + uri : bcs::from_bytes(script.args().get(2)?).ok()?, + }) + } else { + None + } +} + +pub fn aptos_token_unfreeze_transfer_call(payload: &TransactionPayload) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::AptosTokenUnfreezeTransferCall { + collection : bcs::from_bytes(script.args().get(0)?).ok()?, + name : bcs::from_bytes(script.args().get(1)?).ok()?, + }) + } else { + None + } +} + +pub fn aptos_token_update_property_call(payload: &TransactionPayload) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::AptosTokenUpdatePropertyCall { + collection : bcs::from_bytes(script.args().get(0)?).ok()?, + name : bcs::from_bytes(script.args().get(1)?).ok()?, + key : bcs::from_bytes(script.args().get(2)?).ok()?, + type : bcs::from_bytes(script.args().get(3)?).ok()?, + value : bcs::from_bytes(script.args().get(4)?).ok()?, + }) + } else { + None + } +} + +pub fn collection_create_collection(payload: &TransactionPayload) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::CollectionCreateCollection { + description : bcs::from_bytes(script.args().get(0)?).ok()?, + name : bcs::from_bytes(script.args().get(1)?).ok()?, + uri : bcs::from_bytes(script.args().get(2)?).ok()?, + max_supply : bcs::from_bytes(script.args().get(3)?).ok()?, + enable_royalty : bcs::from_bytes(script.args().get(4)?).ok()?, + royalty_numerator : bcs::from_bytes(script.args().get(5)?).ok()?, + royalty_denominator : bcs::from_bytes(script.args().get(6)?).ok()?, + royalty_payee_address : bcs::from_bytes(script.args().get(7)?).ok()?, + }) + } else { + None + } +} +} + +type EntryFunctionDecoderMap = std::collections::HashMap Option + std::marker::Sync + std::marker::Send>>; + +static SCRIPT_FUNCTION_DECODER_MAP: once_cell::sync::Lazy = once_cell::sync::Lazy::new(|| { + let mut map : EntryFunctionDecoderMap = std::collections::HashMap::new(); + map.insert("aptos_token_add_property_call".to_string(), Box::new(decoder::aptos_token_add_property_call)); + map.insert("aptos_token_burn_call".to_string(), Box::new(decoder::aptos_token_burn_call)); + map.insert("aptos_token_create_collection".to_string(), Box::new(decoder::aptos_token_create_collection)); + map.insert("aptos_token_freeze_transfer_call".to_string(), Box::new(decoder::aptos_token_freeze_transfer_call)); + map.insert("aptos_token_mint".to_string(), Box::new(decoder::aptos_token_mint)); + map.insert("aptos_token_mint_soul_bound".to_string(), Box::new(decoder::aptos_token_mint_soul_bound)); + map.insert("aptos_token_remove_property_call".to_string(), Box::new(decoder::aptos_token_remove_property_call)); + map.insert("aptos_token_set_collection_description_call".to_string(), Box::new(decoder::aptos_token_set_collection_description_call)); + map.insert("aptos_token_set_collection_royalties_call".to_string(), Box::new(decoder::aptos_token_set_collection_royalties_call)); + map.insert("aptos_token_set_collection_uri_call".to_string(), Box::new(decoder::aptos_token_set_collection_uri_call)); + map.insert("aptos_token_set_description_call".to_string(), Box::new(decoder::aptos_token_set_description_call)); + map.insert("aptos_token_set_name_call".to_string(), Box::new(decoder::aptos_token_set_name_call)); + map.insert("aptos_token_set_uri_call".to_string(), Box::new(decoder::aptos_token_set_uri_call)); + map.insert("aptos_token_unfreeze_transfer_call".to_string(), Box::new(decoder::aptos_token_unfreeze_transfer_call)); + map.insert("aptos_token_update_property_call".to_string(), Box::new(decoder::aptos_token_update_property_call)); + map.insert("collection_create_collection".to_string(), Box::new(decoder::collection_create_collection)); + map +}); diff --git a/aptos-move/framework/src/aptos.rs b/aptos-move/framework/src/aptos.rs index 90616474e195e..845756d18fd24 100644 --- a/aptos-move/framework/src/aptos.rs +++ b/aptos-move/framework/src/aptos.rs @@ -67,6 +67,10 @@ impl ReleaseTarget { "aptos-token", Some("cached-packages/src/aptos_token_sdk_builder.rs"), ), + ( + "aptos-token-objects", + Some("cached-packages/src/aptos_token_objects_sdk_builder.rs"), + ), ]; // Currently we don't have experimental packages only included in particular targets. result @@ -168,12 +172,14 @@ static NAMED_ADDRESSES: Lazy> = Lazy::new(|| let mut result = BTreeMap::new(); let zero = NumericalAddress::parse_str("0x0").unwrap(); let one = NumericalAddress::parse_str("0x1").unwrap(); - let two = NumericalAddress::parse_str("0x2").unwrap(); + let three = NumericalAddress::parse_str("0x3").unwrap(); + let four = NumericalAddress::parse_str("0x4").unwrap(); let resources = NumericalAddress::parse_str("0xA550C18").unwrap(); result.insert("std".to_owned(), one); result.insert("aptos_std".to_owned(), one); result.insert("aptos_framework".to_owned(), one); - result.insert("aptos_token".to_owned(), two); + result.insert("aptos_token".to_owned(), three); + result.insert("aptos_token_objects".to_owned(), four); result.insert("core_resources".to_owned(), resources); result.insert("vm_reserved".to_owned(), zero); result diff --git a/aptos-move/framework/tests/move_unit_test.rs b/aptos-move/framework/tests/move_unit_test.rs index c8583531a88e0..f71d3b633e81c 100644 --- a/aptos-move/framework/tests/move_unit_test.rs +++ b/aptos-move/framework/tests/move_unit_test.rs @@ -66,3 +66,8 @@ fn move_stdlib_unit_tests() { fn move_token_unit_tests() { run_tests_for_pkg("aptos-token"); } + +#[test] +fn move_token_objects_unit_tests() { + run_tests_for_pkg("aptos-token-objects"); +} diff --git a/aptos-move/move-examples/token_objects/Move.toml b/aptos-move/move-examples/token_objects/Move.toml index 37d121899a9ad..b816afb63d495 100644 --- a/aptos-move/move-examples/token_objects/Move.toml +++ b/aptos-move/move-examples/token_objects/Move.toml @@ -7,3 +7,4 @@ token_objects = "_" [dependencies] AptosFramework = { local = "../../framework/aptos-framework" } +AptosTokenObjects = { local = "../../framework/aptos-token-objects" } diff --git a/aptos-move/move-examples/token_objects/sources/hero.move b/aptos-move/move-examples/token_objects/sources/hero.move index 5484ed4eebc16..b5f639a447550 100644 --- a/aptos-move/move-examples/token_objects/sources/hero.move +++ b/aptos-move/move-examples/token_objects/sources/hero.move @@ -6,8 +6,8 @@ module token_objects::hero { use aptos_framework::object::{Self, ConstructorRef, Object}; - use token_objects::collection; - use token_objects::token; + use aptos_token_objects::collection; + use aptos_token_objects::token; const ENOT_A_HERO: u64 = 1; const ENOT_A_WEAPON: u64 = 2; From ab1c8840722e8bd03f381f8ead8f76a1bd776577 Mon Sep 17 00:00:00 2001 From: David Wolinsky Date: Thu, 23 Mar 2023 16:10:58 -0700 Subject: [PATCH 02/13] [framework] burn property map on token burn --- .../sources/aptos_token.move | 80 +++++++------------ .../sources/property_map.move | 6 +- 2 files changed, 36 insertions(+), 50 deletions(-) diff --git a/aptos-move/framework/aptos-token-objects/sources/aptos_token.move b/aptos-move/framework/aptos-token-objects/sources/aptos_token.move index 5c70cc0c27504..b62819a7aa2d3 100644 --- a/aptos-move/framework/aptos-token-objects/sources/aptos_token.move +++ b/aptos-move/framework/aptos-token-objects/sources/aptos_token.move @@ -67,7 +67,7 @@ module aptos_token_objects::aptos_token { /// Used to mutate fields mutator_ref: Option, /// Used to mutate properties - property_mutator_ref: Option, + property_mutator_ref: property_map::MutatorRef, } /// Create a new collection @@ -231,17 +231,11 @@ module aptos_token_objects::aptos_token { option::none() }; - let property_mutator_ref = if (collection.mutable_token_properties) { - option::some(property_map::generate_mutator_ref(&constructor_ref)) - } else { - option::none() - }; - let aptos_token = AptosToken { burn_ref, transfer_ref: option::none(), mutator_ref, - property_mutator_ref, + property_mutator_ref: property_map::generate_mutator_ref(&constructor_ref), }; move_to(&object_signer, aptos_token); @@ -262,8 +256,9 @@ module aptos_token_objects::aptos_token { borrow_global(token_address) } - public fun are_properties_mutable(token: Object): bool acquires AptosToken { - option::is_some(&borrow(&token).property_mutator_ref) + public fun are_properties_mutable(token: Object): bool acquires AptosCollection { + let collection = token::collection_object(token); + borrow_collection(&collection).mutable_token_properties } public fun is_burnable(token: Object): bool acquires AptosToken { @@ -314,8 +309,9 @@ module aptos_token_objects::aptos_token { burn_ref, transfer_ref: _, mutator_ref: _, - property_mutator_ref: _, + property_mutator_ref, } = aptos_token; + property_map::burn(property_mutator_ref); token::burn(option::extract(&mut burn_ref)); } @@ -382,19 +378,14 @@ module aptos_token_objects::aptos_token { key: String, type: String, value: vector, - ) acquires AptosToken { + ) acquires AptosCollection, AptosToken { let aptos_token = authorized_borrow(&token, signer::address_of(creator)); assert!( - option::is_some(&aptos_token.property_mutator_ref), + are_properties_mutable(token), error::permission_denied(EPROPERTIES_NOT_MUTABLE), ); - property_map::add( - option::borrow(&aptos_token.property_mutator_ref), - key, - type, - value, - ); + property_map::add(&aptos_token.property_mutator_ref, key, type, value); } public fun add_typed_property( @@ -402,28 +393,28 @@ module aptos_token_objects::aptos_token { token: Object, key: String, value: V, - ) acquires AptosToken { + ) acquires AptosCollection, AptosToken { let aptos_token = authorized_borrow(&token, signer::address_of(creator)); assert!( - option::is_some(&aptos_token.property_mutator_ref), + are_properties_mutable(token), error::permission_denied(EPROPERTIES_NOT_MUTABLE), ); - property_map::add_typed( - option::borrow(&aptos_token.property_mutator_ref), - key, - value, - ); + property_map::add_typed(&aptos_token.property_mutator_ref, key, value); } - public fun remove_property(creator: &signer, token: Object, key: &String) acquires AptosToken { + public fun remove_property( + creator: &signer, + token: Object, + key: &String, + ) acquires AptosCollection, AptosToken { let aptos_token = authorized_borrow(&token, signer::address_of(creator)); assert!( - option::is_some(&aptos_token.property_mutator_ref), + are_properties_mutable(token), error::permission_denied(EPROPERTIES_NOT_MUTABLE), ); - property_map::remove(option::borrow(&aptos_token.property_mutator_ref), key); + property_map::remove(&aptos_token.property_mutator_ref, key); } public fun update_property( @@ -432,19 +423,14 @@ module aptos_token_objects::aptos_token { key: &String, type: String, value: vector, - ) acquires AptosToken { + ) acquires AptosCollection, AptosToken { let aptos_token = authorized_borrow(&token, signer::address_of(creator)); assert!( - option::is_some(&aptos_token.property_mutator_ref), + are_properties_mutable(token), error::permission_denied(EPROPERTIES_NOT_MUTABLE), ); - property_map::update( - option::borrow(&aptos_token.property_mutator_ref), - key, - type, - value, - ); + property_map::update(&aptos_token.property_mutator_ref, key, type, value); } public fun update_typed_property( @@ -452,18 +438,14 @@ module aptos_token_objects::aptos_token { token: Object, key: &String, value: V, - ) acquires AptosToken { + ) acquires AptosCollection, AptosToken { let aptos_token = authorized_borrow(&token, signer::address_of(creator)); assert!( - option::is_some(&aptos_token.property_mutator_ref), + are_properties_mutable(token), error::permission_denied(EPROPERTIES_NOT_MUTABLE), ); - property_map::update_typed( - option::borrow(&aptos_token.property_mutator_ref), - key, - value, - ); + property_map::update_typed(&aptos_token.property_mutator_ref, key, value); } // Token entry functions @@ -531,7 +513,7 @@ module aptos_token_objects::aptos_token { key: String, type: String, value: vector, - ) acquires AptosToken { + ) acquires AptosCollection, AptosToken { let token = token_object(creator, &collection, &name); add_property(creator, token, key, type, value); } @@ -542,7 +524,7 @@ module aptos_token_objects::aptos_token { name: String, key: String, value: T, - ) acquires AptosToken { + ) acquires AptosCollection, AptosToken { let token = token_object(creator, &collection, &name); add_typed_property(creator, token, key, value); } @@ -552,7 +534,7 @@ module aptos_token_objects::aptos_token { collection: String, name: String, key: String, - ) acquires AptosToken { + ) acquires AptosCollection, AptosToken { let token = token_object(creator, &collection, &name); remove_property(creator, token, &key); } @@ -564,7 +546,7 @@ module aptos_token_objects::aptos_token { key: String, type: String, value: vector, - ) acquires AptosToken { + ) acquires AptosCollection, AptosToken { let token = token_object(creator, &collection, &name); update_property(creator, token, &key, type, value); } @@ -575,7 +557,7 @@ module aptos_token_objects::aptos_token { name: String, key: String, value: T, - ) acquires AptosToken { + ) acquires AptosCollection, AptosToken { let token = token_object(creator, &collection, &name); update_typed_property(creator, token, &key, value); } diff --git a/aptos-move/framework/aptos-token-objects/sources/property_map.move b/aptos-move/framework/aptos-token-objects/sources/property_map.move index 0435efa183608..0324feb82eb77 100644 --- a/aptos-move/framework/aptos-token-objects/sources/property_map.move +++ b/aptos-move/framework/aptos-token-objects/sources/property_map.move @@ -49,7 +49,7 @@ module aptos_token_objects::property_map { // Structs #[resource_group_member(group = aptos_framework::object::ObjectGroup)] - struct PropertyMap has key { + struct PropertyMap has drop, key { inner: SimpleMap, } @@ -67,6 +67,10 @@ module aptos_token_objects::property_map { move_to(&signer, container); } + public fun burn(ref: MutatorRef) acquires PropertyMap { + move_from(ref.self); + } + /// Helper for external entry functions to produce a valid container for property values. public fun prepare_input( keys: vector, From 19ad7fbe410639d8d85ade0ae5058b0159d2f377 Mon Sep 17 00:00:00 2001 From: David Wolinsky Date: Sun, 19 Mar 2023 09:31:54 -0700 Subject: [PATCH 03/13] [framework] cleanups for token after auditing and documenting --- .../aptos-token-objects/doc/aptos_token.md | 80 ++++++--------- .../aptos-token-objects/doc/collection.md | 97 +++---------------- .../aptos-token-objects/doc/property_map.md | 27 +++++- .../aptos-token-objects/doc/royalty.md | 1 + .../aptos-token-objects/doc/token.md | 39 +++----- .../sources/collection.move | 62 ++---------- .../sources/property_map.move | 1 + .../aptos-token-objects/sources/royalty.move | 1 + .../aptos-token-objects/sources/token.move | 47 +++------ .../src/aptos_token_objects_sdk_builder.rs | 44 --------- 10 files changed, 112 insertions(+), 287 deletions(-) diff --git a/aptos-move/framework/aptos-token-objects/doc/aptos_token.md b/aptos-move/framework/aptos-token-objects/doc/aptos_token.md index eb434cd319cb3..08bc0bf3a706e 100644 --- a/aptos-move/framework/aptos-token-objects/doc/aptos_token.md +++ b/aptos-move/framework/aptos-token-objects/doc/aptos_token.md @@ -196,7 +196,7 @@ Storage state for managing the no-code Token. Used to mutate fields
-property_mutator_ref: option::Option<property_map::MutatorRef> +property_mutator_ref: property_map::MutatorRef
Used to mutate properties @@ -505,17 +505,11 @@ With an existing collection, directly mint a soul bound token into the recipient option::none() }; - let property_mutator_ref = if (collection.mutable_token_properties) { - option::some(property_map::generate_mutator_ref(&constructor_ref)) - } else { - option::none() - }; - let aptos_token = AptosToken { burn_ref, transfer_ref: option::none(), mutator_ref, - property_mutator_ref, + property_mutator_ref: property_map::generate_mutator_ref(&constructor_ref), }; move_to(&object_signer, aptos_token); @@ -545,8 +539,9 @@ With an existing collection, directly mint a soul bound token into the recipient Implementation -
public fun are_properties_mutable<T: key>(token: Object<T>): bool acquires AptosToken {
-    option::is_some(&borrow(&token).property_mutator_ref)
+
public fun are_properties_mutable<T: key>(token: Object<T>): bool acquires AptosCollection {
+    let collection = token::collection_object(token);
+    borrow_collection(&collection).mutable_token_properties
 }
 
@@ -701,8 +696,9 @@ With an existing collection, directly mint a soul bound token into the recipient burn_ref, transfer_ref: _, mutator_ref: _, - property_mutator_ref: _, + property_mutator_ref, } = aptos_token; + property_map::burn(property_mutator_ref); token::burn(option::extract(&mut burn_ref)); }
@@ -889,19 +885,14 @@ With an existing collection, directly mint a soul bound token into the recipient key: String, type: String, value: vector<u8>, -) acquires AptosToken { +) acquires AptosCollection, AptosToken { let aptos_token = authorized_borrow(&token, signer::address_of(creator)); assert!( - option::is_some(&aptos_token.property_mutator_ref), + are_properties_mutable(token), error::permission_denied(EPROPERTIES_NOT_MUTABLE), ); - property_map::add( - option::borrow(&aptos_token.property_mutator_ref), - key, - type, - value, - ); + property_map::add(&aptos_token.property_mutator_ref, key, type, value); } @@ -929,18 +920,14 @@ With an existing collection, directly mint a soul bound token into the recipient token: Object<T>, key: String, value: V, -) acquires AptosToken { +) acquires AptosCollection, AptosToken { let aptos_token = authorized_borrow(&token, signer::address_of(creator)); assert!( - option::is_some(&aptos_token.property_mutator_ref), + are_properties_mutable(token), error::permission_denied(EPROPERTIES_NOT_MUTABLE), ); - property_map::add_typed( - option::borrow(&aptos_token.property_mutator_ref), - key, - value, - ); + property_map::add_typed(&aptos_token.property_mutator_ref, key, value); } @@ -963,14 +950,18 @@ With an existing collection, directly mint a soul bound token into the recipient Implementation -
public fun remove_property<T: key>(creator: &signer, token: Object<T>, key: &String) acquires AptosToken {
+
public fun remove_property<T: key>(
+    creator: &signer,
+    token: Object<T>,
+    key: &String,
+) acquires AptosCollection, AptosToken {
     let aptos_token = authorized_borrow(&token, signer::address_of(creator));
     assert!(
-        option::is_some(&aptos_token.property_mutator_ref),
+        are_properties_mutable(token),
         error::permission_denied(EPROPERTIES_NOT_MUTABLE),
     );
 
-    property_map::remove(option::borrow(&aptos_token.property_mutator_ref), key);
+    property_map::remove(&aptos_token.property_mutator_ref, key);
 }
 
@@ -999,19 +990,14 @@ With an existing collection, directly mint a soul bound token into the recipient key: &String, type: String, value: vector<u8>, -) acquires AptosToken { +) acquires AptosCollection, AptosToken { let aptos_token = authorized_borrow(&token, signer::address_of(creator)); assert!( - option::is_some(&aptos_token.property_mutator_ref), + are_properties_mutable(token), error::permission_denied(EPROPERTIES_NOT_MUTABLE), ); - property_map::update( - option::borrow(&aptos_token.property_mutator_ref), - key, - type, - value, - ); + property_map::update(&aptos_token.property_mutator_ref, key, type, value); }
@@ -1039,18 +1025,14 @@ With an existing collection, directly mint a soul bound token into the recipient token: Object<T>, key: &String, value: V, -) acquires AptosToken { +) acquires AptosCollection, AptosToken { let aptos_token = authorized_borrow(&token, signer::address_of(creator)); assert!( - option::is_some(&aptos_token.property_mutator_ref), + are_properties_mutable(token), error::permission_denied(EPROPERTIES_NOT_MUTABLE), ); - property_map::update_typed( - option::borrow(&aptos_token.property_mutator_ref), - key, - value, - ); + property_map::update_typed(&aptos_token.property_mutator_ref, key, value); } @@ -1251,7 +1233,7 @@ With an existing collection, directly mint a soul bound token into the recipient key: String, type: String, value: vector<u8>, -) acquires AptosToken { +) acquires AptosCollection, AptosToken { let token = token_object(creator, &collection, &name); add_property(creator, token, key, type, value); } @@ -1282,7 +1264,7 @@ With an existing collection, directly mint a soul bound token into the recipient name: String, key: String, value: T, -) acquires AptosToken { +) acquires AptosCollection, AptosToken { let token = token_object(creator, &collection, &name); add_typed_property(creator, token, key, value); } @@ -1312,7 +1294,7 @@ With an existing collection, directly mint a soul bound token into the recipient collection: String, name: String, key: String, -) acquires AptosToken { +) acquires AptosCollection, AptosToken { let token = token_object(creator, &collection, &name); remove_property(creator, token, &key); } @@ -1344,7 +1326,7 @@ With an existing collection, directly mint a soul bound token into the recipient key: String, type: String, value: vector<u8>, -) acquires AptosToken { +) acquires AptosCollection, AptosToken { let token = token_object(creator, &collection, &name); update_property(creator, token, &key, type, value); } @@ -1375,7 +1357,7 @@ With an existing collection, directly mint a soul bound token into the recipient name: String, key: String, value: T, -) acquires AptosToken { +) acquires AptosCollection, AptosToken { let token = token_object(creator, &collection, &name); update_typed_property(creator, token, &key, value); } diff --git a/aptos-move/framework/aptos-token-objects/doc/collection.md b/aptos-move/framework/aptos-token-objects/doc/collection.md index e64db7a33f243..dbe52641b6cd7 100644 --- a/aptos-move/framework/aptos-token-objects/doc/collection.md +++ b/aptos-move/framework/aptos-token-objects/doc/collection.md @@ -28,8 +28,8 @@ require adding the field original_name. - [Resource `Collection`](#0x4_collection_Collection) -- [Struct `MutationEvent`](#0x4_collection_MutationEvent) - [Struct `MutatorRef`](#0x4_collection_MutatorRef) +- [Struct `MutationEvent`](#0x4_collection_MutationEvent) - [Resource `FixedSupply`](#0x4_collection_FixedSupply) - [Constants](#@Constants_0) - [Function `create_fixed_collection`](#0x4_collection_create_fixed_collection) @@ -38,7 +38,6 @@ require adding the field original_name. - [Function `create_collection_seed`](#0x4_collection_create_collection_seed) - [Function `increment_supply`](#0x4_collection_increment_supply) - [Function `decrement_supply`](#0x4_collection_decrement_supply) -- [Function `create_collection`](#0x4_collection_create_collection) - [Function `generate_mutator_ref`](#0x4_collection_generate_mutator_ref) - [Function `count`](#0x4_collection_count) - [Function `creator`](#0x4_collection_creator) @@ -113,15 +112,14 @@ Represents the common fields for a collection. - + -## Struct `MutationEvent` +## Struct `MutatorRef` -Contains the mutated fields name. This makes the life of indexers easier, so that they can -directly understand the behavior in a writeset. +This enables mutating description and URI by higher level services. -
struct MutationEvent has drop, store
+
struct MutatorRef has drop, store
 
@@ -132,7 +130,7 @@ directly understand the behavior in a writeset.
-mutated_field_name: string::String +self: address
@@ -142,14 +140,15 @@ directly understand the behavior in a writeset. - + -## Struct `MutatorRef` +## Struct `MutationEvent` -This enables mutating description and URI by higher level services. +Contains the mutated fields name. This makes the life of indexers easier, so that they can +directly understand the behavior in a writeset. -
struct MutatorRef has drop, store
+
struct MutationEvent has drop, store
 
@@ -160,7 +159,7 @@ This enables mutating description and URI by higher level services.
-self: address +mutated_field_name: string::String
@@ -438,68 +437,6 @@ Called by token on burn to decrement supply if there's an appropriate Supply str - - - - -## Function `create_collection` - -Entry function for creating a collection - - -
public entry fun create_collection(creator: &signer, description: string::String, name: string::String, uri: string::String, max_supply: u64, enable_royalty: bool, royalty_numerator: u64, royalty_denominator: u64, royalty_payee_address: address)
-
- - - -
-Implementation - - -
public entry fun create_collection(
-    creator: &signer,
-    description: String,
-    name: String,
-    uri: String,
-    max_supply: u64,
-    enable_royalty: bool,
-    royalty_numerator: u64,
-    royalty_denominator: u64,
-    royalty_payee_address: address,
-) {
-    let royalty = if (enable_royalty) {
-        option::some(royalty::create(
-            royalty_numerator,
-            royalty_denominator,
-            royalty_payee_address,
-        ))
-    } else {
-        option::none()
-    };
-
-    if (max_supply == 0) {
-        create_untracked_collection(
-            creator,
-            description,
-            name,
-            royalty,
-            uri,
-        )
-    } else {
-        create_fixed_collection(
-            creator,
-            description,
-            max_supply,
-            name,
-            royalty,
-            uri,
-        )
-    };
-}
-
- - -
@@ -674,10 +611,7 @@ Creates a MutatorRef, which gates the ability to mutate any fields that support Implementation -
public fun set_description(
-    mutator_ref: &MutatorRef,
-    description: String,
-) acquires Collection {
+
public fun set_description(mutator_ref: &MutatorRef, description: String) acquires Collection {
     let collection = borrow_mut(mutator_ref);
     collection.description = description;
     event::emit_event(
@@ -706,10 +640,7 @@ Creates a MutatorRef, which gates the ability to mutate any fields that support
 Implementation
 
 
-
public fun set_uri(
-    mutator_ref: &MutatorRef,
-    uri: String,
-) acquires Collection {
+
public fun set_uri(mutator_ref: &MutatorRef, uri: String) acquires Collection {
     let collection = borrow_mut(mutator_ref);
     collection.uri = uri;
     event::emit_event(
diff --git a/aptos-move/framework/aptos-token-objects/doc/property_map.md b/aptos-move/framework/aptos-token-objects/doc/property_map.md
index 4115b702df9b5..8ab1b5390cb44 100644
--- a/aptos-move/framework/aptos-token-objects/doc/property_map.md
+++ b/aptos-move/framework/aptos-token-objects/doc/property_map.md
@@ -13,6 +13,7 @@ represent types and storing values in bcs format.
 -  [Struct `MutatorRef`](#0x4_property_map_MutatorRef)
 -  [Constants](#@Constants_0)
 -  [Function `init`](#0x4_property_map_init)
+-  [Function `burn`](#0x4_property_map_burn)
 -  [Function `prepare_input`](#0x4_property_map_prepare_input)
 -  [Function `generate_mutator_ref`](#0x4_property_map_generate_mutator_ref)
 -  [Function `contains_key`](#0x4_property_map_contains_key)
@@ -55,7 +56,7 @@ represent types and storing values in bcs format.
 
 
 
-
struct PropertyMap has key
+
struct PropertyMap has drop, key
 
@@ -352,6 +353,30 @@ Invalid type specified + + + + +## Function `burn` + + + +
public fun burn(ref: property_map::MutatorRef)
+
+ + + +
+Implementation + + +
public fun burn(ref: MutatorRef) acquires PropertyMap {
+    move_from<PropertyMap>(ref.self);
+}
+
+ + +
diff --git a/aptos-move/framework/aptos-token-objects/doc/royalty.md b/aptos-move/framework/aptos-token-objects/doc/royalty.md index 520a259eb7e52..0736f4d912b38 100644 --- a/aptos-move/framework/aptos-token-objects/doc/royalty.md +++ b/aptos-move/framework/aptos-token-objects/doc/royalty.md @@ -75,6 +75,7 @@ The royalty of a token within this collection -- this optional ## Struct `MutatorRef` +This enables creating or overwriting a MutatorRef.
struct MutatorRef has drop, store
diff --git a/aptos-move/framework/aptos-token-objects/doc/token.md b/aptos-move/framework/aptos-token-objects/doc/token.md
index cc3cbdd3a8736..bc204c4349caf 100644
--- a/aptos-move/framework/aptos-token-objects/doc/token.md
+++ b/aptos-move/framework/aptos-token-objects/doc/token.md
@@ -15,8 +15,8 @@ TODO:
 
 -  [Resource `Token`](#0x4_token_Token)
 -  [Struct `BurnRef`](#0x4_token_BurnRef)
--  [Struct `MutationEvent`](#0x4_token_MutationEvent)
 -  [Struct `MutatorRef`](#0x4_token_MutatorRef)
+-  [Struct `MutationEvent`](#0x4_token_MutationEvent)
 -  [Constants](#@Constants_0)
 -  [Function `create`](#0x4_token_create)
 -  [Function `create_token_address`](#0x4_token_create_token_address)
@@ -154,15 +154,14 @@ a small optimization to support either and take a fixed amount of 34-bytes.
 
 
 
-
+
 
-## Struct `MutationEvent`
+## Struct `MutatorRef`
 
-Contains the mutated fields name. This makes the life of indexers easier, so that they can
-directly understand the behavior in a writeset.
+This enables mutating descritpion and URI by higher level services.
 
 
-
struct MutationEvent has drop, store
+
struct MutatorRef has drop, store
 
@@ -173,7 +172,7 @@ directly understand the behavior in a writeset.
-mutated_field_name: string::String +self: address
@@ -183,14 +182,15 @@ directly understand the behavior in a writeset. - + -## Struct `MutatorRef` +## Struct `MutationEvent` -This enables mutating descritpion and URI by higher level services. +Contains the mutated fields name. This makes the life of indexers easier, so that they can +directly understand the behavior in a writeset. -
struct MutatorRef has drop, store
+
struct MutationEvent has drop, store
 
@@ -201,7 +201,7 @@ This enables mutating descritpion and URI by higher level services.
-self: address +mutated_field_name: string::String
@@ -711,10 +711,7 @@ Extracts the tokens address from a BurnRef. Implementation -
public fun set_description(
-    mutator_ref: &MutatorRef,
-    description: String,
-) acquires Token {
+
public fun set_description(mutator_ref: &MutatorRef, description: String) acquires Token {
     let token = borrow_mut(mutator_ref);
     token.description = description;
     event::emit_event(
@@ -743,10 +740,7 @@ Extracts the tokens address from a BurnRef.
 Implementation
 
 
-
public fun set_name(
-    mutator_ref: &MutatorRef,
-    name: String,
-) acquires Token {
+
public fun set_name(mutator_ref: &MutatorRef, name: String) acquires Token {
     let token = borrow_mut(mutator_ref);
     if (option::is_none(&token.creation_name)) {
         option::fill(&mut token.creation_name, token.name)
@@ -778,10 +772,7 @@ Extracts the tokens address from a BurnRef.
 Implementation
 
 
-
public fun set_uri(
-    mutator_ref: &MutatorRef,
-    uri: String,
-) acquires Token {
+
public fun set_uri(mutator_ref: &MutatorRef, uri: String) acquires Token {
     let token = borrow_mut(mutator_ref);
     token.uri = uri;
     event::emit_event(
diff --git a/aptos-move/framework/aptos-token-objects/sources/collection.move b/aptos-move/framework/aptos-token-objects/sources/collection.move
index b37d0a9b87f92..cf9041eeba481 100644
--- a/aptos-move/framework/aptos-token-objects/sources/collection.move
+++ b/aptos-move/framework/aptos-token-objects/sources/collection.move
@@ -54,17 +54,17 @@ module aptos_token_objects::collection {
         mutation_events: event::EventHandle,
     }
 
+    /// This enables mutating description and URI by higher level services.
+    struct MutatorRef has drop, store {
+        self: address,
+    }
+
     /// Contains the mutated fields name. This makes the life of indexers easier, so that they can
     /// directly understand the behavior in a writeset.
     struct MutationEvent has drop, store {
         mutated_field_name: String,
     }
 
-    /// This enables mutating description and URI by higher level services.
-    struct MutatorRef has drop, store {
-        self: address,
-    }
-
     #[resource_group_member(group = aptos_framework::object::ObjectGroup)]
     /// Fixed supply tracker, this is useful for ensuring that a limited number of tokens are minted.
     struct FixedSupply has key {
@@ -192,48 +192,6 @@ module aptos_token_objects::collection {
         }
     }
 
-    /// Entry function for creating a collection
-    public entry fun create_collection(
-        creator: &signer,
-        description: String,
-        name: String,
-        uri: String,
-        max_supply: u64,
-        enable_royalty: bool,
-        royalty_numerator: u64,
-        royalty_denominator: u64,
-        royalty_payee_address: address,
-    ) {
-        let royalty = if (enable_royalty) {
-            option::some(royalty::create(
-                royalty_numerator,
-                royalty_denominator,
-                royalty_payee_address,
-            ))
-        } else {
-            option::none()
-        };
-
-        if (max_supply == 0) {
-            create_untracked_collection(
-                creator,
-                description,
-                name,
-                royalty,
-                uri,
-            )
-        } else {
-            create_fixed_collection(
-                creator,
-                description,
-                max_supply,
-                name,
-                royalty,
-                uri,
-            )
-        };
-    }
-
     /// Creates a MutatorRef, which gates the ability to mutate any fields that support mutation.
     public fun generate_mutator_ref(ref: &ConstructorRef): MutatorRef {
         let object = object::object_from_constructor_ref(ref);
@@ -292,10 +250,7 @@ module aptos_token_objects::collection {
         borrow_global_mut(mutator_ref.self)
     }
 
-    public fun set_description(
-        mutator_ref: &MutatorRef,
-        description: String,
-    ) acquires Collection {
+    public fun set_description(mutator_ref: &MutatorRef, description: String) acquires Collection {
         let collection = borrow_mut(mutator_ref);
         collection.description = description;
         event::emit_event(
@@ -304,10 +259,7 @@ module aptos_token_objects::collection {
         );
     }
 
-    public fun set_uri(
-        mutator_ref: &MutatorRef,
-        uri: String,
-    ) acquires Collection {
+    public fun set_uri(mutator_ref: &MutatorRef, uri: String) acquires Collection {
         let collection = borrow_mut(mutator_ref);
         collection.uri = uri;
         event::emit_event(
diff --git a/aptos-move/framework/aptos-token-objects/sources/property_map.move b/aptos-move/framework/aptos-token-objects/sources/property_map.move
index 0324feb82eb77..c21d6bf3ac1b1 100644
--- a/aptos-move/framework/aptos-token-objects/sources/property_map.move
+++ b/aptos-move/framework/aptos-token-objects/sources/property_map.move
@@ -35,6 +35,7 @@ module aptos_token_objects::property_map {
     const MAX_PROPERTY_MAP_SIZE: u64 = 1000;
     const MAX_PROPERTY_NAME_LENGTH: u64 = 128;
 
+    // PropertyValue::type
     const BOOL: u8 = 0;
     const U8: u8 = 1;
     const U16: u8 = 2;
diff --git a/aptos-move/framework/aptos-token-objects/sources/royalty.move b/aptos-move/framework/aptos-token-objects/sources/royalty.move
index 82a53c1a13f12..e27be8ad59483 100644
--- a/aptos-move/framework/aptos-token-objects/sources/royalty.move
+++ b/aptos-move/framework/aptos-token-objects/sources/royalty.move
@@ -26,6 +26,7 @@ module aptos_token_objects::royalty {
         payee_address: address,
     }
 
+    /// This enables creating or overwriting a MutatorRef.
     struct MutatorRef has drop, store {
         inner: ExtendRef,
     }
diff --git a/aptos-move/framework/aptos-token-objects/sources/token.move b/aptos-move/framework/aptos-token-objects/sources/token.move
index 31b0f321d0b9c..1b4be5d1b27f7 100644
--- a/aptos-move/framework/aptos-token-objects/sources/token.move
+++ b/aptos-move/framework/aptos-token-objects/sources/token.move
@@ -56,17 +56,17 @@ module aptos_token_objects::token {
         self: Option
, } + /// This enables mutating descritpion and URI by higher level services. + struct MutatorRef has drop, store { + self: address, + } + /// Contains the mutated fields name. This makes the life of indexers easier, so that they can /// directly understand the behavior in a writeset. struct MutationEvent has drop, store { mutated_field_name: String, } - /// This enables mutating descritpion and URI by higher level services. - struct MutatorRef has drop, store { - self: address, - } - /// Creates a new token object and returns the ConstructorRef for additional specialization. public fun create( creator: &signer, @@ -239,10 +239,7 @@ module aptos_token_objects::token { collection::decrement_supply(&collection); } - public fun set_description( - mutator_ref: &MutatorRef, - description: String, - ) acquires Token { + public fun set_description(mutator_ref: &MutatorRef, description: String) acquires Token { let token = borrow_mut(mutator_ref); token.description = description; event::emit_event( @@ -251,10 +248,7 @@ module aptos_token_objects::token { ); } - public fun set_name( - mutator_ref: &MutatorRef, - name: String, - ) acquires Token { + public fun set_name(mutator_ref: &MutatorRef, name: String) acquires Token { let token = borrow_mut(mutator_ref); if (option::is_none(&token.creation_name)) { option::fill(&mut token.creation_name, token.name) @@ -266,10 +260,7 @@ module aptos_token_objects::token { ); } - public fun set_uri( - mutator_ref: &MutatorRef, - uri: String, - ) acquires Token { + public fun set_uri(mutator_ref: &MutatorRef, uri: String) acquires Token { let token = borrow_mut(mutator_ref); token.uri = uri; event::emit_event( @@ -302,16 +293,15 @@ module aptos_token_objects::token { let collection_name = string::utf8(b"collection name"); let token_name = string::utf8(b"token name"); - collection::create_collection( + let creator_address = signer::address_of(creator); + let expected_royalty = royalty::create(10, 1000, creator_address); + collection::create_fixed_collection( creator, string::utf8(b"collection description"), + 5, collection_name, + option::some(expected_royalty), string::utf8(b"collection uri"), - 5, - true, - 10, - 1000, - signer::address_of(creator), ); create( @@ -323,10 +313,8 @@ module aptos_token_objects::token { string::utf8(b"token uri"), ); - let creator_address = signer::address_of(creator); let token_addr = create_token_address(&creator_address, &collection_name, &token_name); let token = object::address_to_object(token_addr); - let expected_royalty = royalty::create(10, 1000, creator_address); assert!(option::some(expected_royalty) == royalty(token), 0); } @@ -484,16 +472,13 @@ module aptos_token_objects::token { #[test_only] fun create_collection_helper(creator: &signer, collection_name: String, max_supply: u64) { - collection::create_collection( + collection::create_fixed_collection( creator, string::utf8(b"collection description"), + max_supply, collection_name, + option::none(), string::utf8(b"collection uri"), - max_supply, - false, - 0, - 0, - signer::address_of(creator), ); } diff --git a/aptos-move/framework/cached-packages/src/aptos_token_objects_sdk_builder.rs b/aptos-move/framework/cached-packages/src/aptos_token_objects_sdk_builder.rs index 6de4f579e6676..dc364ddd1f5fb 100644 --- a/aptos-move/framework/cached-packages/src/aptos_token_objects_sdk_builder.rs +++ b/aptos-move/framework/cached-packages/src/aptos_token_objects_sdk_builder.rs @@ -158,18 +158,6 @@ pub enum EntryFunctionCall { type: Vec, value: Vec, }, - - /// Entry function for creating a collection - CollectionCreateCollection { - description: Vec, - name: Vec, - uri: Vec, - max_supply: u64, - enable_royalty: bool, - royalty_numerator: u64, - royalty_denominator: u64, - royalty_payee_address: AccountAddress, - }, } @@ -194,7 +182,6 @@ impl EntryFunctionCall { AptosTokenSetUriCall{collection, name, uri} => aptos_token_set_uri_call(collection, name, uri), AptosTokenUnfreezeTransferCall{collection, name} => aptos_token_unfreeze_transfer_call(collection, name), AptosTokenUpdatePropertyCall{collection, name, key, type, value} => aptos_token_update_property_call(collection, name, key, type, value), - CollectionCreateCollection{description, name, uri, max_supply, enable_royalty, royalty_numerator, royalty_denominator, royalty_payee_address} => collection_create_collection(description, name, uri, max_supply, enable_royalty, royalty_numerator, royalty_denominator, royalty_payee_address), } } @@ -407,19 +394,6 @@ pub fn aptos_token_update_property_call(collection: Vec, name: Vec, key: vec![bcs::to_bytes(&collection).unwrap(), bcs::to_bytes(&name).unwrap(), bcs::to_bytes(&key).unwrap(), bcs::to_bytes(&type).unwrap(), bcs::to_bytes(&value).unwrap()], )) } - -/// Entry function for creating a collection -pub fn collection_create_collection(description: Vec, name: Vec, uri: Vec, max_supply: u64, enable_royalty: bool, royalty_numerator: u64, royalty_denominator: u64, royalty_payee_address: AccountAddress) -> 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, 4]), - ident_str!("collection").to_owned(), - ), - ident_str!("create_collection").to_owned(), - vec![], - vec![bcs::to_bytes(&description).unwrap(), bcs::to_bytes(&name).unwrap(), bcs::to_bytes(&uri).unwrap(), bcs::to_bytes(&max_supply).unwrap(), bcs::to_bytes(&enable_royalty).unwrap(), bcs::to_bytes(&royalty_numerator).unwrap(), bcs::to_bytes(&royalty_denominator).unwrap(), bcs::to_bytes(&royalty_payee_address).unwrap()], - )) -} mod decoder { use super::*; pub fn aptos_token_add_property_call(payload: &TransactionPayload) -> Option { if let TransactionPayload::EntryFunction(script) = payload { @@ -621,23 +595,6 @@ pub fn aptos_token_update_property_call(payload: &TransactionPayload) -> Option< None } } - -pub fn collection_create_collection(payload: &TransactionPayload) -> Option { - if let TransactionPayload::EntryFunction(script) = payload { - Some(EntryFunctionCall::CollectionCreateCollection { - description : bcs::from_bytes(script.args().get(0)?).ok()?, - name : bcs::from_bytes(script.args().get(1)?).ok()?, - uri : bcs::from_bytes(script.args().get(2)?).ok()?, - max_supply : bcs::from_bytes(script.args().get(3)?).ok()?, - enable_royalty : bcs::from_bytes(script.args().get(4)?).ok()?, - royalty_numerator : bcs::from_bytes(script.args().get(5)?).ok()?, - royalty_denominator : bcs::from_bytes(script.args().get(6)?).ok()?, - royalty_payee_address : bcs::from_bytes(script.args().get(7)?).ok()?, - }) - } else { - None - } -} } type EntryFunctionDecoderMap = std::collections::HashMap Option + std::marker::Sync + std::marker::Send>>; @@ -659,6 +616,5 @@ static SCRIPT_FUNCTION_DECODER_MAP: once_cell::sync::Lazy Date: Thu, 23 Mar 2023 16:32:20 -0700 Subject: [PATCH 04/13] [framework] Propertymap proper errors and renaming entry function param --- .../aptos-token-objects/doc/aptos_token.md | 12 +- .../sources/aptos_token.move | 8 +- .../sources/property_map.move | 4 +- .../src/aptos_token_objects_sdk_builder.rs | 1003 +++++++++++------ 4 files changed, 696 insertions(+), 331 deletions(-) diff --git a/aptos-move/framework/aptos-token-objects/doc/aptos_token.md b/aptos-move/framework/aptos-token-objects/doc/aptos_token.md index 08bc0bf3a706e..a1f211a25fd91 100644 --- a/aptos-move/framework/aptos-token-objects/doc/aptos_token.md +++ b/aptos-move/framework/aptos-token-objects/doc/aptos_token.md @@ -1217,7 +1217,7 @@ With an existing collection, directly mint a soul bound token into the recipient -
entry fun add_property_call(creator: &signer, collection: string::String, name: string::String, key: string::String, type: string::String, value: vector<u8>)
+
entry fun add_property_call(creator: &signer, collection: string::String, name: string::String, key: string::String, type_: string::String, value: vector<u8>)
 
@@ -1231,11 +1231,11 @@ With an existing collection, directly mint a soul bound token into the recipient collection: String, name: String, key: String, - type: String, + type_: String, value: vector<u8>, ) acquires AptosCollection, AptosToken { let token = token_object(creator, &collection, &name); - add_property(creator, token, key, type, value); + add_property(creator, token, key, type_, value); }
@@ -1310,7 +1310,7 @@ With an existing collection, directly mint a soul bound token into the recipient -
entry fun update_property_call(creator: &signer, collection: string::String, name: string::String, key: string::String, type: string::String, value: vector<u8>)
+
entry fun update_property_call(creator: &signer, collection: string::String, name: string::String, key: string::String, type_: string::String, value: vector<u8>)
 
@@ -1324,11 +1324,11 @@ With an existing collection, directly mint a soul bound token into the recipient collection: String, name: String, key: String, - type: String, + type_: String, value: vector<u8>, ) acquires AptosCollection, AptosToken { let token = token_object(creator, &collection, &name); - update_property(creator, token, &key, type, value); + update_property(creator, token, &key, type_, value); }
diff --git a/aptos-move/framework/aptos-token-objects/sources/aptos_token.move b/aptos-move/framework/aptos-token-objects/sources/aptos_token.move index b62819a7aa2d3..51ffc1b46ddb3 100644 --- a/aptos-move/framework/aptos-token-objects/sources/aptos_token.move +++ b/aptos-move/framework/aptos-token-objects/sources/aptos_token.move @@ -511,11 +511,11 @@ module aptos_token_objects::aptos_token { collection: String, name: String, key: String, - type: String, + type_: String, value: vector, ) acquires AptosCollection, AptosToken { let token = token_object(creator, &collection, &name); - add_property(creator, token, key, type, value); + add_property(creator, token, key, type_, value); } entry fun add_typed_property_call( @@ -544,11 +544,11 @@ module aptos_token_objects::aptos_token { collection: String, name: String, key: String, - type: String, + type_: String, value: vector, ) acquires AptosCollection, AptosToken { let token = token_object(creator, &collection, &name); - update_property(creator, token, &key, type, value); + update_property(creator, token, &key, type_, value); } entry fun update_typed_property_call( diff --git a/aptos-move/framework/aptos-token-objects/sources/property_map.move b/aptos-move/framework/aptos-token-objects/sources/property_map.move index c21d6bf3ac1b1..e9d0950983c27 100644 --- a/aptos-move/framework/aptos-token-objects/sources/property_map.move +++ b/aptos-move/framework/aptos-token-objects/sources/property_map.move @@ -247,7 +247,7 @@ module aptos_token_objects::property_map { let (type, value) = read(object, key); assert!( type == type_info::type_name(), - error::invalid_argument(ETYPE_INVALID), + error::invalid_argument(ETYPE_MISMATCH), ); value } @@ -585,7 +585,7 @@ module aptos_token_objects::property_map { } #[test(creator = @0x123)] - #[expected_failure(abort_code = 0x10008, location = Self)] + #[expected_failure(abort_code = 0x10005, location = Self)] fun test_invalid_read(creator: &signer) acquires PropertyMap { let constructor_ref = object::create_named_object(creator, b""); let object = object::object_from_constructor_ref(&constructor_ref); diff --git a/aptos-move/framework/cached-packages/src/aptos_token_objects_sdk_builder.rs b/aptos-move/framework/cached-packages/src/aptos_token_objects_sdk_builder.rs index dc364ddd1f5fb..cad622515a0e0 100644 --- a/aptos-move/framework/cached-packages/src/aptos_token_objects_sdk_builder.rs +++ b/aptos-move/framework/cached-packages/src/aptos_token_objects_sdk_builder.rs @@ -1,4 +1,3 @@ - // Copyright © Aptos Foundation // SPDX-License-Identifier: Apache-2.0 @@ -13,14 +12,17 @@ #![allow(dead_code)] #![allow(unused_imports)] -use aptos_types::account_address::{AccountAddress}; -use aptos_types::transaction::{TransactionPayload, EntryFunction}; -use move_core_types::{ident_str}; -use move_core_types::language_storage::{ModuleId, TypeTag}; +use aptos_types::{ + account_address::AccountAddress, + transaction::{EntryFunction, TransactionPayload}, +}; +use move_core_types::{ + ident_str, + language_storage::{ModuleId, TypeTag}, +}; type Bytes = Vec; - /// Structured representation of a call into a known Move entry function. /// ```ignore /// impl EntryFunctionCall { @@ -32,17 +34,14 @@ type Bytes = Vec; #[cfg_attr(feature = "fuzzing", derive(proptest_derive::Arbitrary))] #[cfg_attr(feature = "fuzzing", proptest(no_params))] pub enum EntryFunctionCall { - - AptosTokenAddPropertyCall { collection: Vec, name: Vec, key: Vec, - type: Vec, + type_: Vec, value: Vec, }, - AptosTokenBurnCall { collection: Vec, name: Vec, @@ -67,7 +66,6 @@ pub enum EntryFunctionCall { royalty_denominator: u64, }, - AptosTokenFreezeTransferCall { collection: Vec, name: Vec, @@ -96,20 +94,17 @@ pub enum EntryFunctionCall { soul_bound_to: AccountAddress, }, - AptosTokenRemovePropertyCall { collection: Vec, name: Vec, key: Vec, }, - AptosTokenSetCollectionDescriptionCall { collection: Vec, description: Vec, }, - AptosTokenSetCollectionRoyaltiesCall { collection: Vec, royalty_numerator: u64, @@ -117,79 +112,187 @@ pub enum EntryFunctionCall { payee_address: AccountAddress, }, - AptosTokenSetCollectionUriCall { collection: Vec, uri: Vec, }, - AptosTokenSetDescriptionCall { collection: Vec, name: Vec, description: Vec, }, - AptosTokenSetNameCall { collection: Vec, original_name: Vec, new_name: Vec, }, - AptosTokenSetUriCall { collection: Vec, name: Vec, uri: Vec, }, - AptosTokenUnfreezeTransferCall { collection: Vec, name: Vec, }, - AptosTokenUpdatePropertyCall { collection: Vec, name: Vec, key: Vec, - type: Vec, + type_: Vec, value: Vec, }, } - impl EntryFunctionCall { - /// Build an Aptos `TransactionPayload` from a structured object `EntryFunctionCall`. pub fn encode(self) -> TransactionPayload { use EntryFunctionCall::*; match self { - AptosTokenAddPropertyCall{collection, name, key, type, value} => aptos_token_add_property_call(collection, name, key, type, value), - AptosTokenBurnCall{collection, name} => aptos_token_burn_call(collection, name), - AptosTokenCreateCollection{description, max_supply, name, uri, mutable_description, mutable_royalty, mutable_uri, mutable_token_description, mutable_token_name, mutable_token_properties, mutable_token_uri, tokens_burnable_by_creator, tokens_freezable_by_creator, royalty_numerator, royalty_denominator} => aptos_token_create_collection(description, max_supply, name, uri, mutable_description, mutable_royalty, mutable_uri, mutable_token_description, mutable_token_name, mutable_token_properties, mutable_token_uri, tokens_burnable_by_creator, tokens_freezable_by_creator, royalty_numerator, royalty_denominator), - AptosTokenFreezeTransferCall{collection, name} => aptos_token_freeze_transfer_call(collection, name), - AptosTokenMint{collection, description, name, uri, property_keys, property_types, property_values} => aptos_token_mint(collection, description, name, uri, property_keys, property_types, property_values), - AptosTokenMintSoulBound{collection, description, name, uri, property_keys, property_types, property_values, soul_bound_to} => aptos_token_mint_soul_bound(collection, description, name, uri, property_keys, property_types, property_values, soul_bound_to), - AptosTokenRemovePropertyCall{collection, name, key} => aptos_token_remove_property_call(collection, name, key), - AptosTokenSetCollectionDescriptionCall{collection, description} => aptos_token_set_collection_description_call(collection, description), - AptosTokenSetCollectionRoyaltiesCall{collection, royalty_numerator, royalty_denominator, payee_address} => aptos_token_set_collection_royalties_call(collection, royalty_numerator, royalty_denominator, payee_address), - AptosTokenSetCollectionUriCall{collection, uri} => aptos_token_set_collection_uri_call(collection, uri), - AptosTokenSetDescriptionCall{collection, name, description} => aptos_token_set_description_call(collection, name, description), - AptosTokenSetNameCall{collection, original_name, new_name} => aptos_token_set_name_call(collection, original_name, new_name), - AptosTokenSetUriCall{collection, name, uri} => aptos_token_set_uri_call(collection, name, uri), - AptosTokenUnfreezeTransferCall{collection, name} => aptos_token_unfreeze_transfer_call(collection, name), - AptosTokenUpdatePropertyCall{collection, name, key, type, value} => aptos_token_update_property_call(collection, name, key, type, value), + AptosTokenAddPropertyCall { + collection, + name, + key, + type_, + value, + } => aptos_token_add_property_call(collection, name, key, type_, value), + AptosTokenBurnCall { collection, name } => aptos_token_burn_call(collection, name), + AptosTokenCreateCollection { + description, + max_supply, + name, + uri, + mutable_description, + mutable_royalty, + mutable_uri, + mutable_token_description, + mutable_token_name, + mutable_token_properties, + mutable_token_uri, + tokens_burnable_by_creator, + tokens_freezable_by_creator, + royalty_numerator, + royalty_denominator, + } => aptos_token_create_collection( + description, + max_supply, + name, + uri, + mutable_description, + mutable_royalty, + mutable_uri, + mutable_token_description, + mutable_token_name, + mutable_token_properties, + mutable_token_uri, + tokens_burnable_by_creator, + tokens_freezable_by_creator, + royalty_numerator, + royalty_denominator, + ), + AptosTokenFreezeTransferCall { collection, name } => { + aptos_token_freeze_transfer_call(collection, name) + }, + AptosTokenMint { + collection, + description, + name, + uri, + property_keys, + property_types, + property_values, + } => aptos_token_mint( + collection, + description, + name, + uri, + property_keys, + property_types, + property_values, + ), + AptosTokenMintSoulBound { + collection, + description, + name, + uri, + property_keys, + property_types, + property_values, + soul_bound_to, + } => aptos_token_mint_soul_bound( + collection, + description, + name, + uri, + property_keys, + property_types, + property_values, + soul_bound_to, + ), + AptosTokenRemovePropertyCall { + collection, + name, + key, + } => aptos_token_remove_property_call(collection, name, key), + AptosTokenSetCollectionDescriptionCall { + collection, + description, + } => aptos_token_set_collection_description_call(collection, description), + AptosTokenSetCollectionRoyaltiesCall { + collection, + royalty_numerator, + royalty_denominator, + payee_address, + } => aptos_token_set_collection_royalties_call( + collection, + royalty_numerator, + royalty_denominator, + payee_address, + ), + AptosTokenSetCollectionUriCall { collection, uri } => { + aptos_token_set_collection_uri_call(collection, uri) + }, + AptosTokenSetDescriptionCall { + collection, + name, + description, + } => aptos_token_set_description_call(collection, name, description), + AptosTokenSetNameCall { + collection, + original_name, + new_name, + } => aptos_token_set_name_call(collection, original_name, new_name), + AptosTokenSetUriCall { + collection, + name, + uri, + } => aptos_token_set_uri_call(collection, name, uri), + AptosTokenUnfreezeTransferCall { collection, name } => { + aptos_token_unfreeze_transfer_call(collection, name) + }, + AptosTokenUpdatePropertyCall { + collection, + name, + key, + type_, + value, + } => aptos_token_update_property_call(collection, name, key, type_, value), } } - /// Try to recognize an Aptos `TransactionPayload` and convert it into a structured object `EntryFunctionCall`. pub fn decode(payload: &TransactionPayload) -> Option { if let TransactionPayload::EntryFunction(script) = payload { - match SCRIPT_FUNCTION_DECODER_MAP.get(&format!("{}_{}", script.module().name(), script.function())) { + match SCRIPT_FUNCTION_DECODER_MAP.get(&format!( + "{}_{}", + script.module().name(), + script.function() + )) { Some(decoder) => decoder(payload), None => None, } @@ -197,424 +300,686 @@ impl EntryFunctionCall { None } } - } - -pub fn aptos_token_add_property_call(collection: Vec, name: Vec, key: Vec, type: Vec, value: Vec) -> TransactionPayload { +pub fn aptos_token_add_property_call( + collection: Vec, + name: Vec, + key: Vec, + type_: Vec, + value: Vec, +) -> 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, 4]), - ident_str!("aptos_token").to_owned(), - ), + 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, 4, + ]), + ident_str!("aptos_token").to_owned(), + ), ident_str!("add_property_call").to_owned(), vec![], - vec![bcs::to_bytes(&collection).unwrap(), bcs::to_bytes(&name).unwrap(), bcs::to_bytes(&key).unwrap(), bcs::to_bytes(&type).unwrap(), bcs::to_bytes(&value).unwrap()], + vec![ + bcs::to_bytes(&collection).unwrap(), + bcs::to_bytes(&name).unwrap(), + bcs::to_bytes(&key).unwrap(), + bcs::to_bytes(&type_).unwrap(), + bcs::to_bytes(&value).unwrap(), + ], )) } - pub fn aptos_token_burn_call(collection: Vec, name: Vec) -> 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, 4]), - ident_str!("aptos_token").to_owned(), - ), + 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, 4, + ]), + ident_str!("aptos_token").to_owned(), + ), ident_str!("burn_call").to_owned(), vec![], - vec![bcs::to_bytes(&collection).unwrap(), bcs::to_bytes(&name).unwrap()], + vec![ + bcs::to_bytes(&collection).unwrap(), + bcs::to_bytes(&name).unwrap(), + ], )) } /// Create a new collection -pub fn aptos_token_create_collection(description: Vec, max_supply: u64, name: Vec, uri: Vec, mutable_description: bool, mutable_royalty: bool, mutable_uri: bool, mutable_token_description: bool, mutable_token_name: bool, mutable_token_properties: bool, mutable_token_uri: bool, tokens_burnable_by_creator: bool, tokens_freezable_by_creator: bool, royalty_numerator: u64, royalty_denominator: u64) -> TransactionPayload { +pub fn aptos_token_create_collection( + description: Vec, + max_supply: u64, + name: Vec, + uri: Vec, + mutable_description: bool, + mutable_royalty: bool, + mutable_uri: bool, + mutable_token_description: bool, + mutable_token_name: bool, + mutable_token_properties: bool, + mutable_token_uri: bool, + tokens_burnable_by_creator: bool, + tokens_freezable_by_creator: bool, + royalty_numerator: u64, + royalty_denominator: u64, +) -> 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, 4]), - ident_str!("aptos_token").to_owned(), - ), + 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, 4, + ]), + ident_str!("aptos_token").to_owned(), + ), ident_str!("create_collection").to_owned(), vec![], - vec![bcs::to_bytes(&description).unwrap(), bcs::to_bytes(&max_supply).unwrap(), bcs::to_bytes(&name).unwrap(), bcs::to_bytes(&uri).unwrap(), bcs::to_bytes(&mutable_description).unwrap(), bcs::to_bytes(&mutable_royalty).unwrap(), bcs::to_bytes(&mutable_uri).unwrap(), bcs::to_bytes(&mutable_token_description).unwrap(), bcs::to_bytes(&mutable_token_name).unwrap(), bcs::to_bytes(&mutable_token_properties).unwrap(), bcs::to_bytes(&mutable_token_uri).unwrap(), bcs::to_bytes(&tokens_burnable_by_creator).unwrap(), bcs::to_bytes(&tokens_freezable_by_creator).unwrap(), bcs::to_bytes(&royalty_numerator).unwrap(), bcs::to_bytes(&royalty_denominator).unwrap()], + vec![ + bcs::to_bytes(&description).unwrap(), + bcs::to_bytes(&max_supply).unwrap(), + bcs::to_bytes(&name).unwrap(), + bcs::to_bytes(&uri).unwrap(), + bcs::to_bytes(&mutable_description).unwrap(), + bcs::to_bytes(&mutable_royalty).unwrap(), + bcs::to_bytes(&mutable_uri).unwrap(), + bcs::to_bytes(&mutable_token_description).unwrap(), + bcs::to_bytes(&mutable_token_name).unwrap(), + bcs::to_bytes(&mutable_token_properties).unwrap(), + bcs::to_bytes(&mutable_token_uri).unwrap(), + bcs::to_bytes(&tokens_burnable_by_creator).unwrap(), + bcs::to_bytes(&tokens_freezable_by_creator).unwrap(), + bcs::to_bytes(&royalty_numerator).unwrap(), + bcs::to_bytes(&royalty_denominator).unwrap(), + ], )) } - pub fn aptos_token_freeze_transfer_call(collection: Vec, name: Vec) -> 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, 4]), - ident_str!("aptos_token").to_owned(), - ), + 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, 4, + ]), + ident_str!("aptos_token").to_owned(), + ), ident_str!("freeze_transfer_call").to_owned(), vec![], - vec![bcs::to_bytes(&collection).unwrap(), bcs::to_bytes(&name).unwrap()], + vec![ + bcs::to_bytes(&collection).unwrap(), + bcs::to_bytes(&name).unwrap(), + ], )) } /// With an existing collection, directly mint a viable token into the creators account. -pub fn aptos_token_mint(collection: Vec, description: Vec, name: Vec, uri: Vec, property_keys: Vec>, property_types: Vec>, property_values: Vec>) -> TransactionPayload { +pub fn aptos_token_mint( + collection: Vec, + description: Vec, + name: Vec, + uri: Vec, + property_keys: Vec>, + property_types: Vec>, + property_values: Vec>, +) -> 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, 4]), - ident_str!("aptos_token").to_owned(), - ), + 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, 4, + ]), + ident_str!("aptos_token").to_owned(), + ), ident_str!("mint").to_owned(), vec![], - vec![bcs::to_bytes(&collection).unwrap(), bcs::to_bytes(&description).unwrap(), bcs::to_bytes(&name).unwrap(), bcs::to_bytes(&uri).unwrap(), bcs::to_bytes(&property_keys).unwrap(), bcs::to_bytes(&property_types).unwrap(), bcs::to_bytes(&property_values).unwrap()], + vec![ + bcs::to_bytes(&collection).unwrap(), + bcs::to_bytes(&description).unwrap(), + bcs::to_bytes(&name).unwrap(), + bcs::to_bytes(&uri).unwrap(), + bcs::to_bytes(&property_keys).unwrap(), + bcs::to_bytes(&property_types).unwrap(), + bcs::to_bytes(&property_values).unwrap(), + ], )) } /// With an existing collection, directly mint a soul bound token into the recipient's account. -pub fn aptos_token_mint_soul_bound(collection: Vec, description: Vec, name: Vec, uri: Vec, property_keys: Vec>, property_types: Vec>, property_values: Vec>, soul_bound_to: AccountAddress) -> TransactionPayload { +pub fn aptos_token_mint_soul_bound( + collection: Vec, + description: Vec, + name: Vec, + uri: Vec, + property_keys: Vec>, + property_types: Vec>, + property_values: Vec>, + soul_bound_to: AccountAddress, +) -> 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, 4]), - ident_str!("aptos_token").to_owned(), - ), + 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, 4, + ]), + ident_str!("aptos_token").to_owned(), + ), ident_str!("mint_soul_bound").to_owned(), vec![], - vec![bcs::to_bytes(&collection).unwrap(), bcs::to_bytes(&description).unwrap(), bcs::to_bytes(&name).unwrap(), bcs::to_bytes(&uri).unwrap(), bcs::to_bytes(&property_keys).unwrap(), bcs::to_bytes(&property_types).unwrap(), bcs::to_bytes(&property_values).unwrap(), bcs::to_bytes(&soul_bound_to).unwrap()], + vec![ + bcs::to_bytes(&collection).unwrap(), + bcs::to_bytes(&description).unwrap(), + bcs::to_bytes(&name).unwrap(), + bcs::to_bytes(&uri).unwrap(), + bcs::to_bytes(&property_keys).unwrap(), + bcs::to_bytes(&property_types).unwrap(), + bcs::to_bytes(&property_values).unwrap(), + bcs::to_bytes(&soul_bound_to).unwrap(), + ], )) } - -pub fn aptos_token_remove_property_call(collection: Vec, name: Vec, key: Vec) -> TransactionPayload { +pub fn aptos_token_remove_property_call( + collection: Vec, + name: Vec, + key: Vec, +) -> 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, 4]), - ident_str!("aptos_token").to_owned(), - ), + 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, 4, + ]), + ident_str!("aptos_token").to_owned(), + ), ident_str!("remove_property_call").to_owned(), vec![], - vec![bcs::to_bytes(&collection).unwrap(), bcs::to_bytes(&name).unwrap(), bcs::to_bytes(&key).unwrap()], + vec![ + bcs::to_bytes(&collection).unwrap(), + bcs::to_bytes(&name).unwrap(), + bcs::to_bytes(&key).unwrap(), + ], )) } - -pub fn aptos_token_set_collection_description_call(collection: Vec, description: Vec) -> TransactionPayload { +pub fn aptos_token_set_collection_description_call( + collection: Vec, + description: Vec, +) -> 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, 4]), - ident_str!("aptos_token").to_owned(), - ), + 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, 4, + ]), + ident_str!("aptos_token").to_owned(), + ), ident_str!("set_collection_description_call").to_owned(), vec![], - vec![bcs::to_bytes(&collection).unwrap(), bcs::to_bytes(&description).unwrap()], + vec![ + bcs::to_bytes(&collection).unwrap(), + bcs::to_bytes(&description).unwrap(), + ], )) } - -pub fn aptos_token_set_collection_royalties_call(collection: Vec, royalty_numerator: u64, royalty_denominator: u64, payee_address: AccountAddress) -> TransactionPayload { +pub fn aptos_token_set_collection_royalties_call( + collection: Vec, + royalty_numerator: u64, + royalty_denominator: u64, + payee_address: AccountAddress, +) -> 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, 4]), - ident_str!("aptos_token").to_owned(), - ), + 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, 4, + ]), + ident_str!("aptos_token").to_owned(), + ), ident_str!("set_collection_royalties_call").to_owned(), vec![], - vec![bcs::to_bytes(&collection).unwrap(), bcs::to_bytes(&royalty_numerator).unwrap(), bcs::to_bytes(&royalty_denominator).unwrap(), bcs::to_bytes(&payee_address).unwrap()], + vec![ + bcs::to_bytes(&collection).unwrap(), + bcs::to_bytes(&royalty_numerator).unwrap(), + bcs::to_bytes(&royalty_denominator).unwrap(), + bcs::to_bytes(&payee_address).unwrap(), + ], )) } - -pub fn aptos_token_set_collection_uri_call(collection: Vec, uri: Vec) -> TransactionPayload { +pub fn aptos_token_set_collection_uri_call( + collection: Vec, + uri: Vec, +) -> 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, 4]), - ident_str!("aptos_token").to_owned(), - ), + 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, 4, + ]), + ident_str!("aptos_token").to_owned(), + ), ident_str!("set_collection_uri_call").to_owned(), vec![], - vec![bcs::to_bytes(&collection).unwrap(), bcs::to_bytes(&uri).unwrap()], + vec![ + bcs::to_bytes(&collection).unwrap(), + bcs::to_bytes(&uri).unwrap(), + ], )) } - -pub fn aptos_token_set_description_call(collection: Vec, name: Vec, description: Vec) -> TransactionPayload { +pub fn aptos_token_set_description_call( + collection: Vec, + name: Vec, + description: Vec, +) -> 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, 4]), - ident_str!("aptos_token").to_owned(), - ), + 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, 4, + ]), + ident_str!("aptos_token").to_owned(), + ), ident_str!("set_description_call").to_owned(), vec![], - vec![bcs::to_bytes(&collection).unwrap(), bcs::to_bytes(&name).unwrap(), bcs::to_bytes(&description).unwrap()], + vec![ + bcs::to_bytes(&collection).unwrap(), + bcs::to_bytes(&name).unwrap(), + bcs::to_bytes(&description).unwrap(), + ], )) } - -pub fn aptos_token_set_name_call(collection: Vec, original_name: Vec, new_name: Vec) -> TransactionPayload { +pub fn aptos_token_set_name_call( + collection: Vec, + original_name: Vec, + new_name: Vec, +) -> 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, 4]), - ident_str!("aptos_token").to_owned(), - ), + 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, 4, + ]), + ident_str!("aptos_token").to_owned(), + ), ident_str!("set_name_call").to_owned(), vec![], - vec![bcs::to_bytes(&collection).unwrap(), bcs::to_bytes(&original_name).unwrap(), bcs::to_bytes(&new_name).unwrap()], + vec![ + bcs::to_bytes(&collection).unwrap(), + bcs::to_bytes(&original_name).unwrap(), + bcs::to_bytes(&new_name).unwrap(), + ], )) } - -pub fn aptos_token_set_uri_call(collection: Vec, name: Vec, uri: Vec) -> TransactionPayload { +pub fn aptos_token_set_uri_call( + collection: Vec, + name: Vec, + uri: Vec, +) -> 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, 4]), - ident_str!("aptos_token").to_owned(), - ), + 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, 4, + ]), + ident_str!("aptos_token").to_owned(), + ), ident_str!("set_uri_call").to_owned(), vec![], - vec![bcs::to_bytes(&collection).unwrap(), bcs::to_bytes(&name).unwrap(), bcs::to_bytes(&uri).unwrap()], + vec![ + bcs::to_bytes(&collection).unwrap(), + bcs::to_bytes(&name).unwrap(), + bcs::to_bytes(&uri).unwrap(), + ], )) } - -pub fn aptos_token_unfreeze_transfer_call(collection: Vec, name: Vec) -> TransactionPayload { +pub fn aptos_token_unfreeze_transfer_call( + collection: Vec, + name: Vec, +) -> 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, 4]), - ident_str!("aptos_token").to_owned(), - ), + 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, 4, + ]), + ident_str!("aptos_token").to_owned(), + ), ident_str!("unfreeze_transfer_call").to_owned(), vec![], - vec![bcs::to_bytes(&collection).unwrap(), bcs::to_bytes(&name).unwrap()], + vec![ + bcs::to_bytes(&collection).unwrap(), + bcs::to_bytes(&name).unwrap(), + ], )) } - -pub fn aptos_token_update_property_call(collection: Vec, name: Vec, key: Vec, type: Vec, value: Vec) -> TransactionPayload { +pub fn aptos_token_update_property_call( + collection: Vec, + name: Vec, + key: Vec, + type_: Vec, + value: Vec, +) -> 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, 4]), - ident_str!("aptos_token").to_owned(), - ), + 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, 4, + ]), + ident_str!("aptos_token").to_owned(), + ), ident_str!("update_property_call").to_owned(), vec![], - vec![bcs::to_bytes(&collection).unwrap(), bcs::to_bytes(&name).unwrap(), bcs::to_bytes(&key).unwrap(), bcs::to_bytes(&type).unwrap(), bcs::to_bytes(&value).unwrap()], + vec![ + bcs::to_bytes(&collection).unwrap(), + bcs::to_bytes(&name).unwrap(), + bcs::to_bytes(&key).unwrap(), + bcs::to_bytes(&type_).unwrap(), + bcs::to_bytes(&value).unwrap(), + ], )) } -mod decoder { use super::*; -pub fn aptos_token_add_property_call(payload: &TransactionPayload) -> Option { - if let TransactionPayload::EntryFunction(script) = payload { - Some(EntryFunctionCall::AptosTokenAddPropertyCall { - collection : bcs::from_bytes(script.args().get(0)?).ok()?, - name : bcs::from_bytes(script.args().get(1)?).ok()?, - key : bcs::from_bytes(script.args().get(2)?).ok()?, - type : bcs::from_bytes(script.args().get(3)?).ok()?, - value : bcs::from_bytes(script.args().get(4)?).ok()?, - }) - } else { - None +mod decoder { + use super::*; + pub fn aptos_token_add_property_call( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::AptosTokenAddPropertyCall { + collection: bcs::from_bytes(script.args().get(0)?).ok()?, + name: bcs::from_bytes(script.args().get(1)?).ok()?, + key: bcs::from_bytes(script.args().get(2)?).ok()?, + type_: bcs::from_bytes(script.args().get(3)?).ok()?, + value: bcs::from_bytes(script.args().get(4)?).ok()?, + }) + } else { + None + } } -} -pub fn aptos_token_burn_call(payload: &TransactionPayload) -> Option { - if let TransactionPayload::EntryFunction(script) = payload { - Some(EntryFunctionCall::AptosTokenBurnCall { - collection : bcs::from_bytes(script.args().get(0)?).ok()?, - name : bcs::from_bytes(script.args().get(1)?).ok()?, - }) - } else { - None + pub fn aptos_token_burn_call(payload: &TransactionPayload) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::AptosTokenBurnCall { + collection: bcs::from_bytes(script.args().get(0)?).ok()?, + name: bcs::from_bytes(script.args().get(1)?).ok()?, + }) + } else { + None + } } -} -pub fn aptos_token_create_collection(payload: &TransactionPayload) -> Option { - if let TransactionPayload::EntryFunction(script) = payload { - Some(EntryFunctionCall::AptosTokenCreateCollection { - description : bcs::from_bytes(script.args().get(0)?).ok()?, - max_supply : bcs::from_bytes(script.args().get(1)?).ok()?, - name : bcs::from_bytes(script.args().get(2)?).ok()?, - uri : bcs::from_bytes(script.args().get(3)?).ok()?, - mutable_description : bcs::from_bytes(script.args().get(4)?).ok()?, - mutable_royalty : bcs::from_bytes(script.args().get(5)?).ok()?, - mutable_uri : bcs::from_bytes(script.args().get(6)?).ok()?, - mutable_token_description : bcs::from_bytes(script.args().get(7)?).ok()?, - mutable_token_name : bcs::from_bytes(script.args().get(8)?).ok()?, - mutable_token_properties : bcs::from_bytes(script.args().get(9)?).ok()?, - mutable_token_uri : bcs::from_bytes(script.args().get(10)?).ok()?, - tokens_burnable_by_creator : bcs::from_bytes(script.args().get(11)?).ok()?, - tokens_freezable_by_creator : bcs::from_bytes(script.args().get(12)?).ok()?, - royalty_numerator : bcs::from_bytes(script.args().get(13)?).ok()?, - royalty_denominator : bcs::from_bytes(script.args().get(14)?).ok()?, - }) - } else { - None + pub fn aptos_token_create_collection( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::AptosTokenCreateCollection { + description: bcs::from_bytes(script.args().get(0)?).ok()?, + max_supply: bcs::from_bytes(script.args().get(1)?).ok()?, + name: bcs::from_bytes(script.args().get(2)?).ok()?, + uri: bcs::from_bytes(script.args().get(3)?).ok()?, + mutable_description: bcs::from_bytes(script.args().get(4)?).ok()?, + mutable_royalty: bcs::from_bytes(script.args().get(5)?).ok()?, + mutable_uri: bcs::from_bytes(script.args().get(6)?).ok()?, + mutable_token_description: bcs::from_bytes(script.args().get(7)?).ok()?, + mutable_token_name: bcs::from_bytes(script.args().get(8)?).ok()?, + mutable_token_properties: bcs::from_bytes(script.args().get(9)?).ok()?, + mutable_token_uri: bcs::from_bytes(script.args().get(10)?).ok()?, + tokens_burnable_by_creator: bcs::from_bytes(script.args().get(11)?).ok()?, + tokens_freezable_by_creator: bcs::from_bytes(script.args().get(12)?).ok()?, + royalty_numerator: bcs::from_bytes(script.args().get(13)?).ok()?, + royalty_denominator: bcs::from_bytes(script.args().get(14)?).ok()?, + }) + } else { + None + } } -} -pub fn aptos_token_freeze_transfer_call(payload: &TransactionPayload) -> Option { - if let TransactionPayload::EntryFunction(script) = payload { - Some(EntryFunctionCall::AptosTokenFreezeTransferCall { - collection : bcs::from_bytes(script.args().get(0)?).ok()?, - name : bcs::from_bytes(script.args().get(1)?).ok()?, - }) - } else { - None + pub fn aptos_token_freeze_transfer_call( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::AptosTokenFreezeTransferCall { + collection: bcs::from_bytes(script.args().get(0)?).ok()?, + name: bcs::from_bytes(script.args().get(1)?).ok()?, + }) + } else { + None + } } -} -pub fn aptos_token_mint(payload: &TransactionPayload) -> Option { - if let TransactionPayload::EntryFunction(script) = payload { - Some(EntryFunctionCall::AptosTokenMint { - collection : bcs::from_bytes(script.args().get(0)?).ok()?, - description : bcs::from_bytes(script.args().get(1)?).ok()?, - name : bcs::from_bytes(script.args().get(2)?).ok()?, - uri : bcs::from_bytes(script.args().get(3)?).ok()?, - property_keys : bcs::from_bytes(script.args().get(4)?).ok()?, - property_types : bcs::from_bytes(script.args().get(5)?).ok()?, - property_values : bcs::from_bytes(script.args().get(6)?).ok()?, - }) - } else { - None + pub fn aptos_token_mint(payload: &TransactionPayload) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::AptosTokenMint { + collection: bcs::from_bytes(script.args().get(0)?).ok()?, + description: bcs::from_bytes(script.args().get(1)?).ok()?, + name: bcs::from_bytes(script.args().get(2)?).ok()?, + uri: bcs::from_bytes(script.args().get(3)?).ok()?, + property_keys: bcs::from_bytes(script.args().get(4)?).ok()?, + property_types: bcs::from_bytes(script.args().get(5)?).ok()?, + property_values: bcs::from_bytes(script.args().get(6)?).ok()?, + }) + } else { + None + } } -} -pub fn aptos_token_mint_soul_bound(payload: &TransactionPayload) -> Option { - if let TransactionPayload::EntryFunction(script) = payload { - Some(EntryFunctionCall::AptosTokenMintSoulBound { - collection : bcs::from_bytes(script.args().get(0)?).ok()?, - description : bcs::from_bytes(script.args().get(1)?).ok()?, - name : bcs::from_bytes(script.args().get(2)?).ok()?, - uri : bcs::from_bytes(script.args().get(3)?).ok()?, - property_keys : bcs::from_bytes(script.args().get(4)?).ok()?, - property_types : bcs::from_bytes(script.args().get(5)?).ok()?, - property_values : bcs::from_bytes(script.args().get(6)?).ok()?, - soul_bound_to : bcs::from_bytes(script.args().get(7)?).ok()?, - }) - } else { - None + pub fn aptos_token_mint_soul_bound(payload: &TransactionPayload) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::AptosTokenMintSoulBound { + collection: bcs::from_bytes(script.args().get(0)?).ok()?, + description: bcs::from_bytes(script.args().get(1)?).ok()?, + name: bcs::from_bytes(script.args().get(2)?).ok()?, + uri: bcs::from_bytes(script.args().get(3)?).ok()?, + property_keys: bcs::from_bytes(script.args().get(4)?).ok()?, + property_types: bcs::from_bytes(script.args().get(5)?).ok()?, + property_values: bcs::from_bytes(script.args().get(6)?).ok()?, + soul_bound_to: bcs::from_bytes(script.args().get(7)?).ok()?, + }) + } else { + None + } } -} -pub fn aptos_token_remove_property_call(payload: &TransactionPayload) -> Option { - if let TransactionPayload::EntryFunction(script) = payload { - Some(EntryFunctionCall::AptosTokenRemovePropertyCall { - collection : bcs::from_bytes(script.args().get(0)?).ok()?, - name : bcs::from_bytes(script.args().get(1)?).ok()?, - key : bcs::from_bytes(script.args().get(2)?).ok()?, - }) - } else { - None + pub fn aptos_token_remove_property_call( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::AptosTokenRemovePropertyCall { + collection: bcs::from_bytes(script.args().get(0)?).ok()?, + name: bcs::from_bytes(script.args().get(1)?).ok()?, + key: bcs::from_bytes(script.args().get(2)?).ok()?, + }) + } else { + None + } } -} -pub fn aptos_token_set_collection_description_call(payload: &TransactionPayload) -> Option { - if let TransactionPayload::EntryFunction(script) = payload { - Some(EntryFunctionCall::AptosTokenSetCollectionDescriptionCall { - collection : bcs::from_bytes(script.args().get(0)?).ok()?, - description : bcs::from_bytes(script.args().get(1)?).ok()?, - }) - } else { - None + pub fn aptos_token_set_collection_description_call( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::AptosTokenSetCollectionDescriptionCall { + collection: bcs::from_bytes(script.args().get(0)?).ok()?, + description: bcs::from_bytes(script.args().get(1)?).ok()?, + }) + } else { + None + } } -} -pub fn aptos_token_set_collection_royalties_call(payload: &TransactionPayload) -> Option { - if let TransactionPayload::EntryFunction(script) = payload { - Some(EntryFunctionCall::AptosTokenSetCollectionRoyaltiesCall { - collection : bcs::from_bytes(script.args().get(0)?).ok()?, - royalty_numerator : bcs::from_bytes(script.args().get(1)?).ok()?, - royalty_denominator : bcs::from_bytes(script.args().get(2)?).ok()?, - payee_address : bcs::from_bytes(script.args().get(3)?).ok()?, - }) - } else { - None + pub fn aptos_token_set_collection_royalties_call( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::AptosTokenSetCollectionRoyaltiesCall { + collection: bcs::from_bytes(script.args().get(0)?).ok()?, + royalty_numerator: bcs::from_bytes(script.args().get(1)?).ok()?, + royalty_denominator: bcs::from_bytes(script.args().get(2)?).ok()?, + payee_address: bcs::from_bytes(script.args().get(3)?).ok()?, + }) + } else { + None + } } -} -pub fn aptos_token_set_collection_uri_call(payload: &TransactionPayload) -> Option { - if let TransactionPayload::EntryFunction(script) = payload { - Some(EntryFunctionCall::AptosTokenSetCollectionUriCall { - collection : bcs::from_bytes(script.args().get(0)?).ok()?, - uri : bcs::from_bytes(script.args().get(1)?).ok()?, - }) - } else { - None + pub fn aptos_token_set_collection_uri_call( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::AptosTokenSetCollectionUriCall { + collection: bcs::from_bytes(script.args().get(0)?).ok()?, + uri: bcs::from_bytes(script.args().get(1)?).ok()?, + }) + } else { + None + } } -} -pub fn aptos_token_set_description_call(payload: &TransactionPayload) -> Option { - if let TransactionPayload::EntryFunction(script) = payload { - Some(EntryFunctionCall::AptosTokenSetDescriptionCall { - collection : bcs::from_bytes(script.args().get(0)?).ok()?, - name : bcs::from_bytes(script.args().get(1)?).ok()?, - description : bcs::from_bytes(script.args().get(2)?).ok()?, - }) - } else { - None + pub fn aptos_token_set_description_call( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::AptosTokenSetDescriptionCall { + collection: bcs::from_bytes(script.args().get(0)?).ok()?, + name: bcs::from_bytes(script.args().get(1)?).ok()?, + description: bcs::from_bytes(script.args().get(2)?).ok()?, + }) + } else { + None + } } -} -pub fn aptos_token_set_name_call(payload: &TransactionPayload) -> Option { - if let TransactionPayload::EntryFunction(script) = payload { - Some(EntryFunctionCall::AptosTokenSetNameCall { - collection : bcs::from_bytes(script.args().get(0)?).ok()?, - original_name : bcs::from_bytes(script.args().get(1)?).ok()?, - new_name : bcs::from_bytes(script.args().get(2)?).ok()?, - }) - } else { - None + pub fn aptos_token_set_name_call(payload: &TransactionPayload) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::AptosTokenSetNameCall { + collection: bcs::from_bytes(script.args().get(0)?).ok()?, + original_name: bcs::from_bytes(script.args().get(1)?).ok()?, + new_name: bcs::from_bytes(script.args().get(2)?).ok()?, + }) + } else { + None + } } -} -pub fn aptos_token_set_uri_call(payload: &TransactionPayload) -> Option { - if let TransactionPayload::EntryFunction(script) = payload { - Some(EntryFunctionCall::AptosTokenSetUriCall { - collection : bcs::from_bytes(script.args().get(0)?).ok()?, - name : bcs::from_bytes(script.args().get(1)?).ok()?, - uri : bcs::from_bytes(script.args().get(2)?).ok()?, - }) - } else { - None + pub fn aptos_token_set_uri_call(payload: &TransactionPayload) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::AptosTokenSetUriCall { + collection: bcs::from_bytes(script.args().get(0)?).ok()?, + name: bcs::from_bytes(script.args().get(1)?).ok()?, + uri: bcs::from_bytes(script.args().get(2)?).ok()?, + }) + } else { + None + } } -} -pub fn aptos_token_unfreeze_transfer_call(payload: &TransactionPayload) -> Option { - if let TransactionPayload::EntryFunction(script) = payload { - Some(EntryFunctionCall::AptosTokenUnfreezeTransferCall { - collection : bcs::from_bytes(script.args().get(0)?).ok()?, - name : bcs::from_bytes(script.args().get(1)?).ok()?, - }) - } else { - None + pub fn aptos_token_unfreeze_transfer_call( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::AptosTokenUnfreezeTransferCall { + collection: bcs::from_bytes(script.args().get(0)?).ok()?, + name: bcs::from_bytes(script.args().get(1)?).ok()?, + }) + } else { + None + } } -} -pub fn aptos_token_update_property_call(payload: &TransactionPayload) -> Option { - if let TransactionPayload::EntryFunction(script) = payload { - Some(EntryFunctionCall::AptosTokenUpdatePropertyCall { - collection : bcs::from_bytes(script.args().get(0)?).ok()?, - name : bcs::from_bytes(script.args().get(1)?).ok()?, - key : bcs::from_bytes(script.args().get(2)?).ok()?, - type : bcs::from_bytes(script.args().get(3)?).ok()?, - value : bcs::from_bytes(script.args().get(4)?).ok()?, - }) - } else { - None + pub fn aptos_token_update_property_call( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::AptosTokenUpdatePropertyCall { + collection: bcs::from_bytes(script.args().get(0)?).ok()?, + name: bcs::from_bytes(script.args().get(1)?).ok()?, + key: bcs::from_bytes(script.args().get(2)?).ok()?, + type_: bcs::from_bytes(script.args().get(3)?).ok()?, + value: bcs::from_bytes(script.args().get(4)?).ok()?, + }) + } else { + None + } } } -} -type EntryFunctionDecoderMap = std::collections::HashMap Option + std::marker::Sync + std::marker::Send>>; - -static SCRIPT_FUNCTION_DECODER_MAP: once_cell::sync::Lazy = once_cell::sync::Lazy::new(|| { - let mut map : EntryFunctionDecoderMap = std::collections::HashMap::new(); - map.insert("aptos_token_add_property_call".to_string(), Box::new(decoder::aptos_token_add_property_call)); - map.insert("aptos_token_burn_call".to_string(), Box::new(decoder::aptos_token_burn_call)); - map.insert("aptos_token_create_collection".to_string(), Box::new(decoder::aptos_token_create_collection)); - map.insert("aptos_token_freeze_transfer_call".to_string(), Box::new(decoder::aptos_token_freeze_transfer_call)); - map.insert("aptos_token_mint".to_string(), Box::new(decoder::aptos_token_mint)); - map.insert("aptos_token_mint_soul_bound".to_string(), Box::new(decoder::aptos_token_mint_soul_bound)); - map.insert("aptos_token_remove_property_call".to_string(), Box::new(decoder::aptos_token_remove_property_call)); - map.insert("aptos_token_set_collection_description_call".to_string(), Box::new(decoder::aptos_token_set_collection_description_call)); - map.insert("aptos_token_set_collection_royalties_call".to_string(), Box::new(decoder::aptos_token_set_collection_royalties_call)); - map.insert("aptos_token_set_collection_uri_call".to_string(), Box::new(decoder::aptos_token_set_collection_uri_call)); - map.insert("aptos_token_set_description_call".to_string(), Box::new(decoder::aptos_token_set_description_call)); - map.insert("aptos_token_set_name_call".to_string(), Box::new(decoder::aptos_token_set_name_call)); - map.insert("aptos_token_set_uri_call".to_string(), Box::new(decoder::aptos_token_set_uri_call)); - map.insert("aptos_token_unfreeze_transfer_call".to_string(), Box::new(decoder::aptos_token_unfreeze_transfer_call)); - map.insert("aptos_token_update_property_call".to_string(), Box::new(decoder::aptos_token_update_property_call)); - map -}); +type EntryFunctionDecoderMap = std::collections::HashMap< + String, + Box< + dyn Fn(&TransactionPayload) -> Option + + std::marker::Sync + + std::marker::Send, + >, +>; + +static SCRIPT_FUNCTION_DECODER_MAP: once_cell::sync::Lazy = + once_cell::sync::Lazy::new(|| { + let mut map: EntryFunctionDecoderMap = std::collections::HashMap::new(); + map.insert( + "aptos_token_add_property_call".to_string(), + Box::new(decoder::aptos_token_add_property_call), + ); + map.insert( + "aptos_token_burn_call".to_string(), + Box::new(decoder::aptos_token_burn_call), + ); + map.insert( + "aptos_token_create_collection".to_string(), + Box::new(decoder::aptos_token_create_collection), + ); + map.insert( + "aptos_token_freeze_transfer_call".to_string(), + Box::new(decoder::aptos_token_freeze_transfer_call), + ); + map.insert( + "aptos_token_mint".to_string(), + Box::new(decoder::aptos_token_mint), + ); + map.insert( + "aptos_token_mint_soul_bound".to_string(), + Box::new(decoder::aptos_token_mint_soul_bound), + ); + map.insert( + "aptos_token_remove_property_call".to_string(), + Box::new(decoder::aptos_token_remove_property_call), + ); + map.insert( + "aptos_token_set_collection_description_call".to_string(), + Box::new(decoder::aptos_token_set_collection_description_call), + ); + map.insert( + "aptos_token_set_collection_royalties_call".to_string(), + Box::new(decoder::aptos_token_set_collection_royalties_call), + ); + map.insert( + "aptos_token_set_collection_uri_call".to_string(), + Box::new(decoder::aptos_token_set_collection_uri_call), + ); + map.insert( + "aptos_token_set_description_call".to_string(), + Box::new(decoder::aptos_token_set_description_call), + ); + map.insert( + "aptos_token_set_name_call".to_string(), + Box::new(decoder::aptos_token_set_name_call), + ); + map.insert( + "aptos_token_set_uri_call".to_string(), + Box::new(decoder::aptos_token_set_uri_call), + ); + map.insert( + "aptos_token_unfreeze_transfer_call".to_string(), + Box::new(decoder::aptos_token_unfreeze_transfer_call), + ); + map.insert( + "aptos_token_update_property_call".to_string(), + Box::new(decoder::aptos_token_update_property_call), + ); + map + }); From 893b32132c50421163c949a6b2e3c9bd9c44bb9d Mon Sep 17 00:00:00 2001 From: David Wolinsky Date: Thu, 23 Mar 2023 21:34:08 -0700 Subject: [PATCH 05/13] [framework] distinguish frozen and soulbound if a user attempts to freeze, unfreeze a soul bound token for which the collection enables freeze, unfreeze, they would get a weird error. --- .../framework/aptos-token-objects/doc/aptos_token.md | 10 ++++++---- .../aptos-token-objects/sources/aptos_token.move | 10 ++++++---- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/aptos-move/framework/aptos-token-objects/doc/aptos_token.md b/aptos-move/framework/aptos-token-objects/doc/aptos_token.md index a1f211a25fd91..ce741c4d5980b 100644 --- a/aptos-move/framework/aptos-token-objects/doc/aptos_token.md +++ b/aptos-move/framework/aptos-token-objects/doc/aptos_token.md @@ -723,11 +723,12 @@ With an existing collection, directly mint a soul bound token into the recipient
public fun freeze_transfer<T: key>(creator: &signer, token: Object<T>) acquires AptosCollection, AptosToken {
+    let aptos_token = authorized_borrow(&token, signer::address_of(creator));
     assert!(
-        are_collection_tokens_freezable(token::collection_object(token)),
+        are_collection_tokens_freezable(token::collection_object(token))
+            && option::is_some(&aptos_token.transfer_ref),
         error::permission_denied(EFIELD_NOT_MUTABLE),
     );
-    let aptos_token = authorized_borrow(&token, signer::address_of(creator));
     object::disable_ungated_transfer(option::borrow(&aptos_token.transfer_ref));
 }
 
@@ -752,11 +753,12 @@ With an existing collection, directly mint a soul bound token into the recipient
public fun unfreeze_transfer<T: key>(creator: &signer, token: Object<T>) acquires AptosCollection, AptosToken {
+    let aptos_token = authorized_borrow(&token, signer::address_of(creator));
     assert!(
-        are_collection_tokens_freezable(token::collection_object(token)),
+        are_collection_tokens_freezable(token::collection_object(token))
+            && option::is_some(&aptos_token.transfer_ref),
         error::permission_denied(EFIELD_NOT_MUTABLE),
     );
-    let aptos_token = authorized_borrow(&token, signer::address_of(creator));
     object::enable_ungated_transfer(option::borrow(&aptos_token.transfer_ref));
 }
 
diff --git a/aptos-move/framework/aptos-token-objects/sources/aptos_token.move b/aptos-move/framework/aptos-token-objects/sources/aptos_token.move index 51ffc1b46ddb3..753916a498fbd 100644 --- a/aptos-move/framework/aptos-token-objects/sources/aptos_token.move +++ b/aptos-move/framework/aptos-token-objects/sources/aptos_token.move @@ -316,20 +316,22 @@ module aptos_token_objects::aptos_token { } public fun freeze_transfer(creator: &signer, token: Object) acquires AptosCollection, AptosToken { + let aptos_token = authorized_borrow(&token, signer::address_of(creator)); assert!( - are_collection_tokens_freezable(token::collection_object(token)), + are_collection_tokens_freezable(token::collection_object(token)) + && option::is_some(&aptos_token.transfer_ref), error::permission_denied(EFIELD_NOT_MUTABLE), ); - let aptos_token = authorized_borrow(&token, signer::address_of(creator)); object::disable_ungated_transfer(option::borrow(&aptos_token.transfer_ref)); } public fun unfreeze_transfer(creator: &signer, token: Object) acquires AptosCollection, AptosToken { + let aptos_token = authorized_borrow(&token, signer::address_of(creator)); assert!( - are_collection_tokens_freezable(token::collection_object(token)), + are_collection_tokens_freezable(token::collection_object(token)) + && option::is_some(&aptos_token.transfer_ref), error::permission_denied(EFIELD_NOT_MUTABLE), ); - let aptos_token = authorized_borrow(&token, signer::address_of(creator)); object::enable_ungated_transfer(option::borrow(&aptos_token.transfer_ref)); } From 0ab5e633d26d0caafa02f0f575660a241cd385d2 Mon Sep 17 00:00:00 2001 From: David Wolinsky Date: Thu, 23 Mar 2023 21:41:14 -0700 Subject: [PATCH 06/13] [framework] kevin doesn't like transferrable collections --- .../framework/aptos-token-objects/sources/collection.move | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/aptos-move/framework/aptos-token-objects/sources/collection.move b/aptos-move/framework/aptos-token-objects/sources/collection.move index cf9041eeba481..994f6eda46287 100644 --- a/aptos-move/framework/aptos-token-objects/sources/collection.move +++ b/aptos-move/framework/aptos-token-objects/sources/collection.move @@ -151,6 +151,9 @@ module aptos_token_objects::collection { royalty::init(&constructor_ref, option::extract(&mut royalty)) }; + let transfer_ref = object::generate_transfer_ref(&constructor_ref); + object::disable_ungated_transfer(&transfer_ref); + constructor_ref } @@ -271,6 +274,7 @@ module aptos_token_objects::collection { // Tests #[test(creator = @0x123, trader = @0x456)] + #[expected_failure(abort_code = 0x50003, location = aptos_framework::object)] entry fun test_create_and_transfer(creator: &signer, trader: &signer) { let creator_address = signer::address_of(creator); let collection_name = string::utf8(b"collection name"); @@ -281,7 +285,6 @@ module aptos_token_objects::collection { ); assert!(object::owner(collection) == creator_address, 1); object::transfer(creator, collection, signer::address_of(trader)); - assert!(object::owner(collection) == signer::address_of(trader), 1); } #[test(creator = @0x123)] From 1cc7090f46d705486846e2700182a263132be1a2 Mon Sep 17 00:00:00 2001 From: David Wolinsky Date: Sat, 25 Mar 2023 16:05:17 -0700 Subject: [PATCH 07/13] [abigen] don't panic if you can't handle runtime generics The current abigen depends on TypeTags to represent abis. Unfortunately this excludes it from representing any generic entry function. That should NOT prevent us from writing these entry functions in Move or in the framework. The current code creates that unnecessary restriction, so instead of panicing, just return none as if it cannot understand it. --- .../move-prover/move-abigen/src/abigen.rs | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/third_party/move/move-prover/move-abigen/src/abigen.rs b/third_party/move/move-prover/move-abigen/src/abigen.rs index eca389e87fa0f..d36d41a16c9ed 100644 --- a/third_party/move/move-prover/move-abigen/src/abigen.rs +++ b/third_party/move/move-prover/move-abigen/src/abigen.rs @@ -286,25 +286,27 @@ impl<'env> Abigen<'env> { TypeTag::Vector(Box::new(tag)) }, Struct(module_id, struct_id, vec_type) => { - let expect_msg = format!("type {:?} is not allowed in scription function", ty0); let struct_module_env = module_env.env.get_module(*module_id); let abilities = struct_module_env.get_struct(*struct_id).get_abilities(); if abilities.has_ability(Ability::Copy) && !abilities.has_ability(Ability::Key) { + let mut type_params = vec![]; + for e in vec_type { + let type_param = match Self::get_type_tag(e, module_env)? { + Some(type_param) => type_param, + None => return Ok(None), + }; + type_params.push(type_param); + } TypeTag::Struct(Box::new(StructTag { address: *struct_module_env.self_address(), module: struct_module_env.get_identifier(), name: struct_module_env .get_struct(*struct_id) .get_identifier() - .unwrap_or_else(|| panic!("{}", expect_msg)), - type_params: vec_type - .iter() - .map(|e| { - Self::get_type_tag(e, module_env) - .unwrap_or_else(|_| panic!("{}", expect_msg)) - }) - .map(|e| e.unwrap_or_else(|| panic!("{}", expect_msg))) - .collect(), + .unwrap_or_else(|| { + panic!("type {:?} is not allowed in entry function", ty0) + }), + type_params, })) } else { return Ok(None); From 4f68f2372b752d51fd748dc441b2f0075ab9b40f Mon Sep 17 00:00:00 2001 From: David Wolinsky Date: Sat, 25 Mar 2023 16:09:15 -0700 Subject: [PATCH 08/13] [framework] remove all non-Object entry functions from AptosToken upgrade to more effective interfaces -- still need to improve both the abigen in move and then the rust sdk builder --- .../aptos-token-objects/doc/aptos_token.md | 488 ++------------ .../sources/aptos_token.move | 275 +++----- .../src/aptos_token_objects_sdk_builder.rs | 611 ------------------ 3 files changed, 121 insertions(+), 1253 deletions(-) diff --git a/aptos-move/framework/aptos-token-objects/doc/aptos_token.md b/aptos-move/framework/aptos-token-objects/doc/aptos_token.md index ce741c4d5980b..f4eb9a1f870cd 100644 --- a/aptos-move/framework/aptos-token-objects/doc/aptos_token.md +++ b/aptos-move/framework/aptos-token-objects/doc/aptos_token.md @@ -37,17 +37,6 @@ The key features are: - [Function `remove_property`](#0x4_aptos_token_remove_property) - [Function `update_property`](#0x4_aptos_token_update_property) - [Function `update_typed_property`](#0x4_aptos_token_update_typed_property) -- [Function `burn_call`](#0x4_aptos_token_burn_call) -- [Function `freeze_transfer_call`](#0x4_aptos_token_freeze_transfer_call) -- [Function `unfreeze_transfer_call`](#0x4_aptos_token_unfreeze_transfer_call) -- [Function `set_description_call`](#0x4_aptos_token_set_description_call) -- [Function `set_name_call`](#0x4_aptos_token_set_name_call) -- [Function `set_uri_call`](#0x4_aptos_token_set_uri_call) -- [Function `add_property_call`](#0x4_aptos_token_add_property_call) -- [Function `add_typed_property_call`](#0x4_aptos_token_add_typed_property_call) -- [Function `remove_property_call`](#0x4_aptos_token_remove_property_call) -- [Function `update_property_call`](#0x4_aptos_token_update_property_call) -- [Function `update_typed_property_call`](#0x4_aptos_token_update_typed_property_call) - [Function `is_mutable_collection_description`](#0x4_aptos_token_is_mutable_collection_description) - [Function `is_mutable_collection_royalty`](#0x4_aptos_token_is_mutable_collection_royalty) - [Function `is_mutable_collection_uri`](#0x4_aptos_token_is_mutable_collection_uri) @@ -59,10 +48,8 @@ The key features are: - [Function `are_collection_tokens_freezable`](#0x4_aptos_token_are_collection_tokens_freezable) - [Function `set_collection_description`](#0x4_aptos_token_set_collection_description) - [Function `set_collection_royalties`](#0x4_aptos_token_set_collection_royalties) -- [Function `set_collection_uri`](#0x4_aptos_token_set_collection_uri) -- [Function `set_collection_description_call`](#0x4_aptos_token_set_collection_description_call) - [Function `set_collection_royalties_call`](#0x4_aptos_token_set_collection_royalties_call) -- [Function `set_collection_uri_call`](#0x4_aptos_token_set_collection_uri_call) +- [Function `set_collection_uri`](#0x4_aptos_token_set_collection_uri)
use 0x1::error;
@@ -675,7 +662,7 @@ With an existing collection, directly mint a soul bound token into the recipient
 
 
 
-
public fun burn<T: key>(creator: &signer, token: object::Object<T>)
+
public entry fun burn<T: key>(creator: &signer, token: object::Object<T>)
 
@@ -684,7 +671,7 @@ With an existing collection, directly mint a soul bound token into the recipient Implementation -
public fun burn<T: key>(creator: &signer, token: Object<T>) acquires AptosToken {
+
public entry fun burn<T: key>(creator: &signer, token: Object<T>) acquires AptosToken {
     let aptos_token = authorized_borrow(&token, signer::address_of(creator));
     assert!(
         option::is_some(&aptos_token.burn_ref),
@@ -713,7 +700,7 @@ With an existing collection, directly mint a soul bound token into the recipient
 
 
 
-
public fun freeze_transfer<T: key>(creator: &signer, token: object::Object<T>)
+
public entry fun freeze_transfer<T: key>(creator: &signer, token: object::Object<T>)
 
@@ -722,7 +709,7 @@ With an existing collection, directly mint a soul bound token into the recipient Implementation -
public fun freeze_transfer<T: key>(creator: &signer, token: Object<T>) acquires AptosCollection, AptosToken {
+
public entry fun freeze_transfer<T: key>(creator: &signer, token: Object<T>) acquires AptosCollection, AptosToken {
     let aptos_token = authorized_borrow(&token, signer::address_of(creator));
     assert!(
         are_collection_tokens_freezable(token::collection_object(token))
@@ -743,7 +730,7 @@ With an existing collection, directly mint a soul bound token into the recipient
 
 
 
-
public fun unfreeze_transfer<T: key>(creator: &signer, token: object::Object<T>)
+
public entry fun unfreeze_transfer<T: key>(creator: &signer, token: object::Object<T>)
 
@@ -752,7 +739,7 @@ With an existing collection, directly mint a soul bound token into the recipient Implementation -
public fun unfreeze_transfer<T: key>(creator: &signer, token: Object<T>) acquires AptosCollection, AptosToken {
+
public entry fun unfreeze_transfer<T: key>(creator: &signer, token: Object<T>) acquires AptosCollection, AptosToken {
     let aptos_token = authorized_borrow(&token, signer::address_of(creator));
     assert!(
         are_collection_tokens_freezable(token::collection_object(token))
@@ -773,7 +760,7 @@ With an existing collection, directly mint a soul bound token into the recipient
 
 
 
-
public fun set_description<T: key>(creator: &signer, token: object::Object<T>, description: string::String)
+
public entry fun set_description<T: key>(creator: &signer, token: object::Object<T>, description: string::String)
 
@@ -782,7 +769,7 @@ With an existing collection, directly mint a soul bound token into the recipient Implementation -
public fun set_description<T: key>(
+
public entry fun set_description<T: key>(
     creator: &signer,
     token: Object<T>,
     description: String,
@@ -806,7 +793,7 @@ With an existing collection, directly mint a soul bound token into the recipient
 
 
 
-
public fun set_name<T: key>(creator: &signer, token: object::Object<T>, name: string::String)
+
public entry fun set_name<T: key>(creator: &signer, token: object::Object<T>, name: string::String)
 
@@ -815,7 +802,7 @@ With an existing collection, directly mint a soul bound token into the recipient Implementation -
public fun set_name<T: key>(
+
public entry fun set_name<T: key>(
     creator: &signer,
     token: Object<T>,
     name: String,
@@ -839,7 +826,7 @@ With an existing collection, directly mint a soul bound token into the recipient
 
 
 
-
public fun set_uri<T: key>(creator: &signer, token: object::Object<T>, uri: string::String)
+
public entry fun set_uri<T: key>(creator: &signer, token: object::Object<T>, uri: string::String)
 
@@ -848,7 +835,7 @@ With an existing collection, directly mint a soul bound token into the recipient Implementation -
public fun set_uri<T: key>(
+
public entry fun set_uri<T: key>(
     creator: &signer,
     token: Object<T>,
     uri: String,
@@ -872,7 +859,7 @@ With an existing collection, directly mint a soul bound token into the recipient
 
 
 
-
public fun add_property<T: key>(creator: &signer, token: object::Object<T>, key: string::String, type: string::String, value: vector<u8>)
+
public entry fun add_property<T: key>(creator: &signer, token: object::Object<T>, key: string::String, type: string::String, value: vector<u8>)
 
@@ -881,7 +868,7 @@ With an existing collection, directly mint a soul bound token into the recipient Implementation -
public fun add_property<T: key>(
+
public entry fun add_property<T: key>(
     creator: &signer,
     token: Object<T>,
     key: String,
@@ -908,7 +895,7 @@ With an existing collection, directly mint a soul bound token into the recipient
 
 
 
-
public fun add_typed_property<T: key, V: drop>(creator: &signer, token: object::Object<T>, key: string::String, value: V)
+
public entry fun add_typed_property<T: key, V: drop>(creator: &signer, token: object::Object<T>, key: string::String, value: V)
 
@@ -917,7 +904,7 @@ With an existing collection, directly mint a soul bound token into the recipient Implementation -
public fun add_typed_property<T: key, V: drop>(
+
public entry fun add_typed_property<T: key, V: drop>(
     creator: &signer,
     token: Object<T>,
     key: String,
@@ -943,7 +930,7 @@ With an existing collection, directly mint a soul bound token into the recipient
 
 
 
-
public fun remove_property<T: key>(creator: &signer, token: object::Object<T>, key: &string::String)
+
public entry fun remove_property<T: key>(creator: &signer, token: object::Object<T>, key: string::String)
 
@@ -952,10 +939,10 @@ With an existing collection, directly mint a soul bound token into the recipient Implementation -
public fun remove_property<T: key>(
+
public entry fun remove_property<T: key>(
     creator: &signer,
     token: Object<T>,
-    key: &String,
+    key: String,
 ) acquires AptosCollection, AptosToken {
     let aptos_token = authorized_borrow(&token, signer::address_of(creator));
     assert!(
@@ -963,7 +950,7 @@ With an existing collection, directly mint a soul bound token into the recipient
         error::permission_denied(EPROPERTIES_NOT_MUTABLE),
     );
 
-    property_map::remove(&aptos_token.property_mutator_ref, key);
+    property_map::remove(&aptos_token.property_mutator_ref, &key);
 }
 
@@ -977,7 +964,7 @@ With an existing collection, directly mint a soul bound token into the recipient -
public fun update_property<T: key>(creator: &signer, token: object::Object<T>, key: &string::String, type: string::String, value: vector<u8>)
+
public entry fun update_property<T: key>(creator: &signer, token: object::Object<T>, key: string::String, type: string::String, value: vector<u8>)
 
@@ -986,10 +973,10 @@ With an existing collection, directly mint a soul bound token into the recipient Implementation -
public fun update_property<T: key>(
+
public entry fun update_property<T: key>(
     creator: &signer,
     token: Object<T>,
-    key: &String,
+    key: String,
     type: String,
     value: vector<u8>,
 ) acquires AptosCollection, AptosToken {
@@ -999,7 +986,7 @@ With an existing collection, directly mint a soul bound token into the recipient
         error::permission_denied(EPROPERTIES_NOT_MUTABLE),
     );
 
-    property_map::update(&aptos_token.property_mutator_ref, key, type, value);
+    property_map::update(&aptos_token.property_mutator_ref, &key, type, value);
 }
 
@@ -1013,7 +1000,7 @@ With an existing collection, directly mint a soul bound token into the recipient -
public fun update_typed_property<T: key, V: drop>(creator: &signer, token: object::Object<T>, key: &string::String, value: V)
+
public entry fun update_typed_property<T: key, V: drop>(creator: &signer, token: object::Object<T>, key: string::String, value: V)
 
@@ -1022,10 +1009,10 @@ With an existing collection, directly mint a soul bound token into the recipient Implementation -
public fun update_typed_property<T: key, V: drop>(
+
public entry fun update_typed_property<T: key, V: drop>(
     creator: &signer,
     token: Object<T>,
-    key: &String,
+    key: String,
     value: V,
 ) acquires AptosCollection, AptosToken {
     let aptos_token = authorized_borrow(&token, signer::address_of(creator));
@@ -1034,334 +1021,7 @@ With an existing collection, directly mint a soul bound token into the recipient
         error::permission_denied(EPROPERTIES_NOT_MUTABLE),
     );
 
-    property_map::update_typed(&aptos_token.property_mutator_ref, key, value);
-}
-
- - - - - - - -## Function `burn_call` - - - -
entry fun burn_call(creator: &signer, collection: string::String, name: string::String)
-
- - - -
-Implementation - - -
entry fun burn_call(
-    creator: &signer,
-    collection: String,
-    name: String,
-) acquires AptosToken {
-    burn(creator, token_object(creator, &collection, &name));
-}
-
- - - -
- - - -## Function `freeze_transfer_call` - - - -
entry fun freeze_transfer_call(creator: &signer, collection: string::String, name: string::String)
-
- - - -
-Implementation - - -
entry fun freeze_transfer_call(
-    creator: &signer,
-    collection: String,
-    name: String,
-) acquires AptosCollection, AptosToken {
-    freeze_transfer(creator, token_object(creator, &collection, &name));
-}
-
- - - -
- - - -## Function `unfreeze_transfer_call` - - - -
entry fun unfreeze_transfer_call(creator: &signer, collection: string::String, name: string::String)
-
- - - -
-Implementation - - -
entry fun unfreeze_transfer_call(
-    creator: &signer,
-    collection: String,
-    name: String,
-) acquires AptosCollection, AptosToken {
-    unfreeze_transfer(creator, token_object(creator, &collection, &name));
-}
-
- - - -
- - - -## Function `set_description_call` - - - -
entry fun set_description_call(creator: &signer, collection: string::String, name: string::String, description: string::String)
-
- - - -
-Implementation - - -
entry fun set_description_call(
-    creator: &signer,
-    collection: String,
-    name: String,
-    description: String,
-) acquires AptosCollection, AptosToken {
-    set_description(creator, token_object(creator, &collection, &name), description);
-}
-
- - - -
- - - -## Function `set_name_call` - - - -
entry fun set_name_call(creator: &signer, collection: string::String, original_name: string::String, new_name: string::String)
-
- - - -
-Implementation - - -
entry fun set_name_call(
-    creator: &signer,
-    collection: String,
-    original_name: String,
-    new_name: String,
-) acquires AptosCollection, AptosToken {
-    set_name(creator, token_object(creator, &collection, &original_name), new_name);
-}
-
- - - -
- - - -## Function `set_uri_call` - - - -
entry fun set_uri_call(creator: &signer, collection: string::String, name: string::String, uri: string::String)
-
- - - -
-Implementation - - -
entry fun set_uri_call(
-    creator: &signer,
-    collection: String,
-    name: String,
-    uri: String,
-) acquires AptosCollection, AptosToken {
-    set_uri(creator, token_object(creator, &collection, &name), uri);
-}
-
- - - -
- - - -## Function `add_property_call` - - - -
entry fun add_property_call(creator: &signer, collection: string::String, name: string::String, key: string::String, type_: string::String, value: vector<u8>)
-
- - - -
-Implementation - - -
entry fun add_property_call(
-    creator: &signer,
-    collection: String,
-    name: String,
-    key: String,
-    type_: String,
-    value: vector<u8>,
-) acquires AptosCollection, AptosToken {
-    let token = token_object(creator, &collection, &name);
-    add_property(creator, token, key, type_, value);
-}
-
- - - -
- - - -## Function `add_typed_property_call` - - - -
entry fun add_typed_property_call<T: drop>(creator: &signer, collection: string::String, name: string::String, key: string::String, value: T)
-
- - - -
-Implementation - - -
entry fun add_typed_property_call<T: drop>(
-    creator: &signer,
-    collection: String,
-    name: String,
-    key: String,
-    value: T,
-) acquires AptosCollection, AptosToken {
-    let token = token_object(creator, &collection, &name);
-    add_typed_property(creator, token, key, value);
-}
-
- - - -
- - - -## Function `remove_property_call` - - - -
entry fun remove_property_call(creator: &signer, collection: string::String, name: string::String, key: string::String)
-
- - - -
-Implementation - - -
entry fun remove_property_call(
-    creator: &signer,
-    collection: String,
-    name: String,
-    key: String,
-) acquires AptosCollection, AptosToken {
-    let token = token_object(creator, &collection, &name);
-    remove_property(creator, token, &key);
-}
-
- - - -
- - - -## Function `update_property_call` - - - -
entry fun update_property_call(creator: &signer, collection: string::String, name: string::String, key: string::String, type_: string::String, value: vector<u8>)
-
- - - -
-Implementation - - -
entry fun update_property_call(
-    creator: &signer,
-    collection: String,
-    name: String,
-    key: String,
-    type_: String,
-    value: vector<u8>,
-) acquires AptosCollection, AptosToken {
-    let token = token_object(creator, &collection, &name);
-    update_property(creator, token, &key, type_, value);
-}
-
- - - -
- - - -## Function `update_typed_property_call` - - - -
entry fun update_typed_property_call<T: drop>(creator: &signer, collection: string::String, name: string::String, key: string::String, value: T)
-
- - - -
-Implementation - - -
entry fun update_typed_property_call<T: drop>(
-    creator: &signer,
-    collection: String,
-    name: String,
-    key: String,
-    value: T,
-) acquires AptosCollection, AptosToken {
-    let token = token_object(creator, &collection, &name);
-    update_typed_property(creator, token, &key, value);
+    property_map::update_typed(&aptos_token.property_mutator_ref, &key, value);
 }
 
@@ -1609,7 +1269,7 @@ With an existing collection, directly mint a soul bound token into the recipient -
public fun set_collection_description<T: key>(creator: &signer, collection: object::Object<T>, description: string::String)
+
public entry fun set_collection_description<T: key>(creator: &signer, collection: object::Object<T>, description: string::String)
 
@@ -1618,7 +1278,7 @@ With an existing collection, directly mint a soul bound token into the recipient Implementation -
public fun set_collection_description<T: key>(
+
public entry fun set_collection_description<T: key>(
     creator: &signer,
     collection: Object<T>,
     description: String,
@@ -1667,67 +1327,6 @@ With an existing collection, directly mint a soul bound token into the recipient
 
 
 
-
- - - -## Function `set_collection_uri` - - - -
public fun set_collection_uri<T: key>(creator: &signer, collection: object::Object<T>, uri: string::String)
-
- - - -
-Implementation - - -
public fun set_collection_uri<T: key>(
-    creator: &signer,
-    collection: Object<T>,
-    uri: String,
-) acquires AptosCollection {
-    let aptos_collection = authorized_borrow_collection(&collection, signer::address_of(creator));
-    assert!(
-        aptos_collection.mutable_uri,
-        error::permission_denied(EFIELD_NOT_MUTABLE),
-    );
-    collection::set_uri(option::borrow(&aptos_collection.mutator_ref), uri);
-}
-
- - - -
- - - -## Function `set_collection_description_call` - - - -
entry fun set_collection_description_call(creator: &signer, collection: string::String, description: string::String)
-
- - - -
-Implementation - - -
entry fun set_collection_description_call(
-    creator: &signer,
-    collection: String,
-    description: String,
-) acquires AptosCollection {
-    set_collection_description(creator, collection_object(creator, &collection), description);
-}
-
- - -
@@ -1736,7 +1335,7 @@ With an existing collection, directly mint a soul bound token into the recipient -
entry fun set_collection_royalties_call(creator: &signer, collection: string::String, royalty_numerator: u64, royalty_denominator: u64, payee_address: address)
+
entry fun set_collection_royalties_call<T: key>(creator: &signer, collection: object::Object<T>, royalty_numerator: u64, royalty_denominator: u64, payee_address: address)
 
@@ -1745,15 +1344,15 @@ With an existing collection, directly mint a soul bound token into the recipient Implementation -
entry fun set_collection_royalties_call(
+
entry fun set_collection_royalties_call<T: key>(
     creator: &signer,
-    collection: String,
+    collection: Object<T>,
     royalty_numerator: u64,
     royalty_denominator: u64,
     payee_address: address,
 ) acquires AptosCollection {
     let royalty = royalty::create(royalty_numerator, royalty_denominator, payee_address);
-    set_collection_royalties(creator, collection_object(creator, &collection), royalty);
+    set_collection_royalties(creator, collection, royalty);
 }
 
@@ -1761,13 +1360,13 @@ With an existing collection, directly mint a soul bound token into the recipient - + -## Function `set_collection_uri_call` +## Function `set_collection_uri` -
entry fun set_collection_uri_call(creator: &signer, collection: string::String, uri: string::String)
+
public entry fun set_collection_uri<T: key>(creator: &signer, collection: object::Object<T>, uri: string::String)
 
@@ -1776,12 +1375,17 @@ With an existing collection, directly mint a soul bound token into the recipient Implementation -
entry fun set_collection_uri_call(
+
public entry fun set_collection_uri<T: key>(
     creator: &signer,
-    collection: String,
+    collection: Object<T>,
     uri: String,
 ) acquires AptosCollection {
-    set_collection_uri(creator, collection_object(creator, &collection), uri);
+    let aptos_collection = authorized_borrow_collection(&collection, signer::address_of(creator));
+    assert!(
+        aptos_collection.mutable_uri,
+        error::permission_denied(EFIELD_NOT_MUTABLE),
+    );
+    collection::set_uri(option::borrow(&aptos_collection.mutator_ref), uri);
 }
 
diff --git a/aptos-move/framework/aptos-token-objects/sources/aptos_token.move b/aptos-move/framework/aptos-token-objects/sources/aptos_token.move index 753916a498fbd..24b8800f54dcc 100644 --- a/aptos-move/framework/aptos-token-objects/sources/aptos_token.move +++ b/aptos-move/framework/aptos-token-objects/sources/aptos_token.move @@ -297,7 +297,7 @@ module aptos_token_objects::aptos_token { borrow_global(token_address) } - public fun burn(creator: &signer, token: Object) acquires AptosToken { + public entry fun burn(creator: &signer, token: Object) acquires AptosToken { let aptos_token = authorized_borrow(&token, signer::address_of(creator)); assert!( option::is_some(&aptos_token.burn_ref), @@ -315,7 +315,7 @@ module aptos_token_objects::aptos_token { token::burn(option::extract(&mut burn_ref)); } - public fun freeze_transfer(creator: &signer, token: Object) acquires AptosCollection, AptosToken { + public entry fun freeze_transfer(creator: &signer, token: Object) acquires AptosCollection, AptosToken { let aptos_token = authorized_borrow(&token, signer::address_of(creator)); assert!( are_collection_tokens_freezable(token::collection_object(token)) @@ -325,7 +325,7 @@ module aptos_token_objects::aptos_token { object::disable_ungated_transfer(option::borrow(&aptos_token.transfer_ref)); } - public fun unfreeze_transfer(creator: &signer, token: Object) acquires AptosCollection, AptosToken { + public entry fun unfreeze_transfer(creator: &signer, token: Object) acquires AptosCollection, AptosToken { let aptos_token = authorized_borrow(&token, signer::address_of(creator)); assert!( are_collection_tokens_freezable(token::collection_object(token)) @@ -335,7 +335,7 @@ module aptos_token_objects::aptos_token { object::enable_ungated_transfer(option::borrow(&aptos_token.transfer_ref)); } - public fun set_description( + public entry fun set_description( creator: &signer, token: Object, description: String, @@ -348,7 +348,7 @@ module aptos_token_objects::aptos_token { token::set_description(option::borrow(&aptos_token.mutator_ref), description); } - public fun set_name( + public entry fun set_name( creator: &signer, token: Object, name: String, @@ -361,7 +361,7 @@ module aptos_token_objects::aptos_token { token::set_name(option::borrow(&aptos_token.mutator_ref), name); } - public fun set_uri( + public entry fun set_uri( creator: &signer, token: Object, uri: String, @@ -374,7 +374,7 @@ module aptos_token_objects::aptos_token { token::set_uri(option::borrow(&aptos_token.mutator_ref), uri); } - public fun add_property( + public entry fun add_property( creator: &signer, token: Object, key: String, @@ -390,7 +390,7 @@ module aptos_token_objects::aptos_token { property_map::add(&aptos_token.property_mutator_ref, key, type, value); } - public fun add_typed_property( + public entry fun add_typed_property( creator: &signer, token: Object, key: String, @@ -405,10 +405,10 @@ module aptos_token_objects::aptos_token { property_map::add_typed(&aptos_token.property_mutator_ref, key, value); } - public fun remove_property( + public entry fun remove_property( creator: &signer, token: Object, - key: &String, + key: String, ) acquires AptosCollection, AptosToken { let aptos_token = authorized_borrow(&token, signer::address_of(creator)); assert!( @@ -416,13 +416,13 @@ module aptos_token_objects::aptos_token { error::permission_denied(EPROPERTIES_NOT_MUTABLE), ); - property_map::remove(&aptos_token.property_mutator_ref, key); + property_map::remove(&aptos_token.property_mutator_ref, &key); } - public fun update_property( + public entry fun update_property( creator: &signer, token: Object, - key: &String, + key: String, type: String, value: vector, ) acquires AptosCollection, AptosToken { @@ -432,13 +432,13 @@ module aptos_token_objects::aptos_token { error::permission_denied(EPROPERTIES_NOT_MUTABLE), ); - property_map::update(&aptos_token.property_mutator_ref, key, type, value); + property_map::update(&aptos_token.property_mutator_ref, &key, type, value); } - public fun update_typed_property( + public entry fun update_typed_property( creator: &signer, token: Object, - key: &String, + key: String, value: V, ) acquires AptosCollection, AptosToken { let aptos_token = authorized_borrow(&token, signer::address_of(creator)); @@ -447,125 +447,16 @@ module aptos_token_objects::aptos_token { error::permission_denied(EPROPERTIES_NOT_MUTABLE), ); - property_map::update_typed(&aptos_token.property_mutator_ref, key, value); - } - - // Token entry functions - - inline fun token_object(creator: &signer, collection: &String, name: &String): Object { - let token_addr = token::create_token_address(&signer::address_of(creator), collection, name); - object::address_to_object(token_addr) - } - - entry fun burn_call( - creator: &signer, - collection: String, - name: String, - ) acquires AptosToken { - burn(creator, token_object(creator, &collection, &name)); - } - - entry fun freeze_transfer_call( - creator: &signer, - collection: String, - name: String, - ) acquires AptosCollection, AptosToken { - freeze_transfer(creator, token_object(creator, &collection, &name)); - } - - entry fun unfreeze_transfer_call( - creator: &signer, - collection: String, - name: String, - ) acquires AptosCollection, AptosToken { - unfreeze_transfer(creator, token_object(creator, &collection, &name)); - } - - entry fun set_description_call( - creator: &signer, - collection: String, - name: String, - description: String, - ) acquires AptosCollection, AptosToken { - set_description(creator, token_object(creator, &collection, &name), description); - } - - entry fun set_name_call( - creator: &signer, - collection: String, - original_name: String, - new_name: String, - ) acquires AptosCollection, AptosToken { - set_name(creator, token_object(creator, &collection, &original_name), new_name); - } - - entry fun set_uri_call( - creator: &signer, - collection: String, - name: String, - uri: String, - ) acquires AptosCollection, AptosToken { - set_uri(creator, token_object(creator, &collection, &name), uri); - } - - entry fun add_property_call( - creator: &signer, - collection: String, - name: String, - key: String, - type_: String, - value: vector, - ) acquires AptosCollection, AptosToken { - let token = token_object(creator, &collection, &name); - add_property(creator, token, key, type_, value); - } - - entry fun add_typed_property_call( - creator: &signer, - collection: String, - name: String, - key: String, - value: T, - ) acquires AptosCollection, AptosToken { - let token = token_object(creator, &collection, &name); - add_typed_property(creator, token, key, value); - } - - entry fun remove_property_call( - creator: &signer, - collection: String, - name: String, - key: String, - ) acquires AptosCollection, AptosToken { - let token = token_object(creator, &collection, &name); - remove_property(creator, token, &key); + property_map::update_typed(&aptos_token.property_mutator_ref, &key, value); } - entry fun update_property_call( - creator: &signer, - collection: String, - name: String, - key: String, - type_: String, - value: vector, - ) acquires AptosCollection, AptosToken { - let token = token_object(creator, &collection, &name); - update_property(creator, token, &key, type_, value); - } + // Collection accessors - entry fun update_typed_property_call( - creator: &signer, - collection: String, - name: String, - key: String, - value: T, - ) acquires AptosCollection, AptosToken { - let token = token_object(creator, &collection, &name); - update_typed_property(creator, token, &key, value); + inline fun collection_object(creator: &signer, name: &String): Object { + let collection_addr = collection::create_collection_address(&signer::address_of(creator), name); + object::address_to_object(collection_addr) } - // Collection accessors - inline fun borrow_collection(token: &Object): &AptosCollection { let collection_address = object::object_address(token); assert!( @@ -644,7 +535,7 @@ module aptos_token_objects::aptos_token { borrow_global(collection_address) } - public fun set_collection_description( + public entry fun set_collection_description( creator: &signer, collection: Object, description: String, @@ -670,55 +561,39 @@ module aptos_token_objects::aptos_token { royalty::update(option::borrow(&aptos_collection.royalty_mutator_ref), royalty); } - public fun set_collection_uri( + entry fun set_collection_royalties_call( creator: &signer, collection: Object, - uri: String, - ) acquires AptosCollection { - let aptos_collection = authorized_borrow_collection(&collection, signer::address_of(creator)); - assert!( - aptos_collection.mutable_uri, - error::permission_denied(EFIELD_NOT_MUTABLE), - ); - collection::set_uri(option::borrow(&aptos_collection.mutator_ref), uri); - } - - // Collection entry functions - - inline fun collection_object(creator: &signer, name: &String): Object { - let collection_addr = collection::create_collection_address(&signer::address_of(creator), name); - object::address_to_object(collection_addr) - } - - entry fun set_collection_description_call( - creator: &signer, - collection: String, - description: String, - ) acquires AptosCollection { - set_collection_description(creator, collection_object(creator, &collection), description); - } - - entry fun set_collection_royalties_call( - creator: &signer, - collection: String, royalty_numerator: u64, royalty_denominator: u64, payee_address: address, ) acquires AptosCollection { let royalty = royalty::create(royalty_numerator, royalty_denominator, payee_address); - set_collection_royalties(creator, collection_object(creator, &collection), royalty); + set_collection_royalties(creator, collection, royalty); } - entry fun set_collection_uri_call( + public entry fun set_collection_uri( creator: &signer, - collection: String, + collection: Object, uri: String, ) acquires AptosCollection { - set_collection_uri(creator, collection_object(creator, &collection), uri); + let aptos_collection = authorized_borrow_collection(&collection, signer::address_of(creator)); + assert!( + aptos_collection.mutable_uri, + error::permission_denied(EFIELD_NOT_MUTABLE), + ); + collection::set_uri(option::borrow(&aptos_collection.mutator_ref), uri); } // Tests + #[test_only] + inline fun token_object(creator: &signer, collection: &String, name: &String): Object { + let token_addr = token::create_token_address(&signer::address_of(creator), collection, name); + object::address_to_object(token_addr) + } + + #[test_only] use std::string; @@ -771,7 +646,7 @@ module aptos_token_objects::aptos_token { create_collection_helper(creator, collection_name, true); let token = mint_helper(creator, collection_name, token_name); - freeze_transfer_call(creator, collection_name, token_name); + freeze_transfer(creator, token); object::transfer(creator, token, @0x345); } @@ -782,8 +657,8 @@ module aptos_token_objects::aptos_token { create_collection_helper(creator, collection_name, true); let token = mint_helper(creator, collection_name, token_name); - freeze_transfer_call(creator, collection_name, token_name); - unfreeze_transfer_call(creator, collection_name, token_name); + freeze_transfer(creator, token); + unfreeze_transfer(creator, token); object::transfer(creator, token, @0x345); } @@ -806,7 +681,7 @@ module aptos_token_objects::aptos_token { create_collection_helper(creator, collection_name, true); let token = mint_helper(creator, collection_name, token_name); - freeze_transfer_call(creator, collection_name, token_name); + freeze_transfer(creator, token); unfreeze_transfer(another, token); } @@ -820,7 +695,7 @@ module aptos_token_objects::aptos_token { let description = string::utf8(b"not"); assert!(token::description(token) != description, 0); - set_description_call(creator, collection_name, token_name, description); + set_description(creator, token, description); assert!(token::description(token) == description, 1); } @@ -831,9 +706,9 @@ module aptos_token_objects::aptos_token { let token_name = string::utf8(b"token name"); create_collection_helper(creator, collection_name, false); - mint_helper(creator, collection_name, token_name); + let token = mint_helper(creator, collection_name, token_name); - set_description_call(creator, collection_name, token_name, string::utf8(b"")); + set_description(creator, token, string::utf8(b"")); } #[test(creator = @0x123, noncreator = @0x456)] @@ -862,7 +737,7 @@ module aptos_token_objects::aptos_token { let name = string::utf8(b"not"); assert!(token::name(token) != name, 0); - set_name_call(creator, collection_name, token_name, name); + set_name(creator, token, name); assert!(token::name(token) == name, 1); } @@ -873,9 +748,9 @@ module aptos_token_objects::aptos_token { let token_name = string::utf8(b"token name"); create_collection_helper(creator, collection_name, false); - mint_helper(creator, collection_name, token_name); + let token = mint_helper(creator, collection_name, token_name); - set_name_call(creator, collection_name, token_name, string::utf8(b"")); + set_name(creator, token, string::utf8(b"")); } #[test(creator = @0x123, noncreator = @0x456)] @@ -904,7 +779,7 @@ module aptos_token_objects::aptos_token { let uri = string::utf8(b"not"); assert!(token::uri(token) != uri, 0); - set_uri_call(creator, collection_name, token_name, uri); + set_uri(creator, token, uri); assert!(token::uri(token) == uri, 1); } @@ -915,9 +790,9 @@ module aptos_token_objects::aptos_token { let token_name = string::utf8(b"token name"); create_collection_helper(creator, collection_name, false); - mint_helper(creator, collection_name, token_name); + let token = mint_helper(creator, collection_name, token_name); - set_uri_call(creator, collection_name, token_name, string::utf8(b"")); + set_uri(creator, token, string::utf8(b"")); } #[test(creator = @0x123, noncreator = @0x456)] @@ -937,7 +812,7 @@ module aptos_token_objects::aptos_token { } #[test(creator = @0x123)] - entry fun test_burnable(creator: &signer) acquires AptosCollection, AptosToken { + fun test_burnable(creator: &signer) acquires AptosCollection, AptosToken { let collection_name = string::utf8(b"collection name"); let token_name = string::utf8(b"token name"); @@ -952,7 +827,7 @@ module aptos_token_objects::aptos_token { #[test(creator = @0x123)] #[expected_failure(abort_code = 0x50004, location = Self)] - entry fun test_not_burnable(creator: &signer) acquires AptosCollection, AptosToken { + fun test_not_burnable(creator: &signer) acquires AptosCollection, AptosToken { let collection_name = string::utf8(b"collection name"); let token_name = string::utf8(b"token name"); @@ -964,7 +839,7 @@ module aptos_token_objects::aptos_token { #[test(creator = @0x123, noncreator = @0x456)] #[expected_failure(abort_code = 0x50002, location = Self)] - entry fun test_burn_non_creator( + fun test_burn_non_creator( creator: &signer, noncreator: &signer, ) acquires AptosCollection, AptosToken { @@ -983,7 +858,7 @@ module aptos_token_objects::aptos_token { let collection = create_collection_helper(creator, collection_name, true); let value = string::utf8(b"not"); assert!(collection::description(collection) != value, 0); - set_collection_description_call(creator, collection_name, value); + set_collection_description(creator, collection, value); assert!(collection::description(collection) == value, 1); } @@ -991,8 +866,8 @@ module aptos_token_objects::aptos_token { #[expected_failure(abort_code = 0x50003, location = Self)] fun test_set_immutable_collection_description(creator: &signer) acquires AptosCollection { let collection_name = string::utf8(b"collection name"); - create_collection_helper(creator, collection_name, false); - set_collection_description_call(creator, collection_name, string::utf8(b"")); + let collection = create_collection_helper(creator, collection_name, false); + set_collection_description(creator, collection, string::utf8(b"")); } #[test(creator = @0x123, noncreator = @0x456)] @@ -1012,7 +887,7 @@ module aptos_token_objects::aptos_token { let collection = create_collection_helper(creator, collection_name, true); let value = string::utf8(b"not"); assert!(collection::uri(collection) != value, 0); - set_collection_uri_call(creator, collection_name, value); + set_collection_uri(creator, collection, value); assert!(collection::uri(collection) == value, 1); } @@ -1020,8 +895,8 @@ module aptos_token_objects::aptos_token { #[expected_failure(abort_code = 0x50003, location = Self)] fun test_set_immutable_collection_uri(creator: &signer) acquires AptosCollection { let collection_name = string::utf8(b"collection name"); - create_collection_helper(creator, collection_name, false); - set_collection_uri_call(creator, collection_name, string::utf8(b"")); + let collection = create_collection_helper(creator, collection_name, false); + set_collection_uri(creator, collection, string::utf8(b"")); } #[test(creator = @0x123, noncreator = @0x456)] @@ -1036,7 +911,7 @@ module aptos_token_objects::aptos_token { } #[test(creator = @0x123)] - entry fun test_property_add(creator: &signer) acquires AptosCollection, AptosToken { + fun test_property_add(creator: &signer) acquires AptosCollection, AptosToken { let collection_name = string::utf8(b"collection name"); let token_name = string::utf8(b"token name"); let property_name = string::utf8(b"u8"); @@ -1044,26 +919,26 @@ module aptos_token_objects::aptos_token { create_collection_helper(creator, collection_name, true); let token = mint_helper(creator, collection_name, token_name); - add_property_call(creator, collection_name, token_name, property_name, property_type, vector [ 0x08 ]); + add_property(creator, token, property_name, property_type, vector [ 0x08 ]); assert!(property_map::read_u8(&token, &property_name) == 0x8, 0); } #[test(creator = @0x123)] - entry fun test_property_typed_add(creator: &signer) acquires AptosCollection, AptosToken { + fun test_property_typed_add(creator: &signer) acquires AptosCollection, AptosToken { let collection_name = string::utf8(b"collection name"); let token_name = string::utf8(b"token name"); let property_name = string::utf8(b"u8"); create_collection_helper(creator, collection_name, true); let token = mint_helper(creator, collection_name, token_name); - add_typed_property_call(creator, collection_name, token_name, property_name, 0x8); + add_typed_property(creator, token, property_name, 0x8); assert!(property_map::read_u8(&token, &property_name) == 0x8, 0); } #[test(creator = @0x123)] - entry fun test_property_update(creator: &signer) acquires AptosCollection, AptosToken { + fun test_property_update(creator: &signer) acquires AptosCollection, AptosToken { let collection_name = string::utf8(b"collection name"); let token_name = string::utf8(b"token name"); let property_name = string::utf8(b"bool"); @@ -1071,45 +946,45 @@ module aptos_token_objects::aptos_token { create_collection_helper(creator, collection_name, true); let token = mint_helper(creator, collection_name, token_name); - update_property_call(creator, collection_name, token_name, property_name, property_type, vector [ 0x00 ]); + update_property(creator, token, property_name, property_type, vector [ 0x00 ]); assert!(!property_map::read_bool(&token, &property_name), 0); } #[test(creator = @0x123)] - entry fun test_property_update_typed(creator: &signer) acquires AptosCollection, AptosToken { + fun test_property_update_typed(creator: &signer) acquires AptosCollection, AptosToken { let collection_name = string::utf8(b"collection name"); let token_name = string::utf8(b"token name"); let property_name = string::utf8(b"bool"); create_collection_helper(creator, collection_name, true); let token = mint_helper(creator, collection_name, token_name); - update_typed_property_call(creator, collection_name, token_name, property_name, false); + update_typed_property(creator, token, property_name, false); assert!(!property_map::read_bool(&token, &property_name), 0); } #[test(creator = @0x123)] - entry fun test_property_remove(creator: &signer) acquires AptosCollection, AptosToken { + fun test_property_remove(creator: &signer) acquires AptosCollection, AptosToken { let collection_name = string::utf8(b"collection name"); let token_name = string::utf8(b"token name"); let property_name = string::utf8(b"bool"); create_collection_helper(creator, collection_name, true); - mint_helper(creator, collection_name, token_name); - remove_property_call(creator, collection_name, token_name, property_name); + let token = mint_helper(creator, collection_name, token_name); + remove_property(creator, token, property_name); } #[test(creator = @0x123)] - entry fun test_royalties(creator: &signer) acquires AptosCollection, AptosToken { + fun test_royalties(creator: &signer) acquires AptosCollection, AptosToken { let collection_name = string::utf8(b"collection name"); let token_name = string::utf8(b"token name"); - create_collection_helper(creator, collection_name, true); + let collection = create_collection_helper(creator, collection_name, true); let token = mint_helper(creator, collection_name, token_name); let royalty_before = option::extract(&mut token::royalty(token)); - set_collection_royalties_call(creator, collection_name, 2, 3, @0x444); + set_collection_royalties_call(creator, collection, 2, 3, @0x444); let royalty_after = option::extract(&mut token::royalty(token)); assert!(royalty_before != royalty_after, 0); } diff --git a/aptos-move/framework/cached-packages/src/aptos_token_objects_sdk_builder.rs b/aptos-move/framework/cached-packages/src/aptos_token_objects_sdk_builder.rs index cad622515a0e0..ee0982cfbf492 100644 --- a/aptos-move/framework/cached-packages/src/aptos_token_objects_sdk_builder.rs +++ b/aptos-move/framework/cached-packages/src/aptos_token_objects_sdk_builder.rs @@ -34,19 +34,6 @@ type Bytes = Vec; #[cfg_attr(feature = "fuzzing", derive(proptest_derive::Arbitrary))] #[cfg_attr(feature = "fuzzing", proptest(no_params))] pub enum EntryFunctionCall { - AptosTokenAddPropertyCall { - collection: Vec, - name: Vec, - key: Vec, - type_: Vec, - value: Vec, - }, - - AptosTokenBurnCall { - collection: Vec, - name: Vec, - }, - /// Create a new collection AptosTokenCreateCollection { description: Vec, @@ -66,11 +53,6 @@ pub enum EntryFunctionCall { royalty_denominator: u64, }, - AptosTokenFreezeTransferCall { - collection: Vec, - name: Vec, - }, - /// With an existing collection, directly mint a viable token into the creators account. AptosTokenMint { collection: Vec, @@ -93,60 +75,6 @@ pub enum EntryFunctionCall { property_values: Vec>, soul_bound_to: AccountAddress, }, - - AptosTokenRemovePropertyCall { - collection: Vec, - name: Vec, - key: Vec, - }, - - AptosTokenSetCollectionDescriptionCall { - collection: Vec, - description: Vec, - }, - - AptosTokenSetCollectionRoyaltiesCall { - collection: Vec, - royalty_numerator: u64, - royalty_denominator: u64, - payee_address: AccountAddress, - }, - - AptosTokenSetCollectionUriCall { - collection: Vec, - uri: Vec, - }, - - AptosTokenSetDescriptionCall { - collection: Vec, - name: Vec, - description: Vec, - }, - - AptosTokenSetNameCall { - collection: Vec, - original_name: Vec, - new_name: Vec, - }, - - AptosTokenSetUriCall { - collection: Vec, - name: Vec, - uri: Vec, - }, - - AptosTokenUnfreezeTransferCall { - collection: Vec, - name: Vec, - }, - - AptosTokenUpdatePropertyCall { - collection: Vec, - name: Vec, - key: Vec, - type_: Vec, - value: Vec, - }, } impl EntryFunctionCall { @@ -154,14 +82,6 @@ impl EntryFunctionCall { pub fn encode(self) -> TransactionPayload { use EntryFunctionCall::*; match self { - AptosTokenAddPropertyCall { - collection, - name, - key, - type_, - value, - } => aptos_token_add_property_call(collection, name, key, type_, value), - AptosTokenBurnCall { collection, name } => aptos_token_burn_call(collection, name), AptosTokenCreateCollection { description, max_supply, @@ -195,9 +115,6 @@ impl EntryFunctionCall { royalty_numerator, royalty_denominator, ), - AptosTokenFreezeTransferCall { collection, name } => { - aptos_token_freeze_transfer_call(collection, name) - }, AptosTokenMint { collection, description, @@ -234,54 +151,6 @@ impl EntryFunctionCall { property_values, soul_bound_to, ), - AptosTokenRemovePropertyCall { - collection, - name, - key, - } => aptos_token_remove_property_call(collection, name, key), - AptosTokenSetCollectionDescriptionCall { - collection, - description, - } => aptos_token_set_collection_description_call(collection, description), - AptosTokenSetCollectionRoyaltiesCall { - collection, - royalty_numerator, - royalty_denominator, - payee_address, - } => aptos_token_set_collection_royalties_call( - collection, - royalty_numerator, - royalty_denominator, - payee_address, - ), - AptosTokenSetCollectionUriCall { collection, uri } => { - aptos_token_set_collection_uri_call(collection, uri) - }, - AptosTokenSetDescriptionCall { - collection, - name, - description, - } => aptos_token_set_description_call(collection, name, description), - AptosTokenSetNameCall { - collection, - original_name, - new_name, - } => aptos_token_set_name_call(collection, original_name, new_name), - AptosTokenSetUriCall { - collection, - name, - uri, - } => aptos_token_set_uri_call(collection, name, uri), - AptosTokenUnfreezeTransferCall { collection, name } => { - aptos_token_unfreeze_transfer_call(collection, name) - }, - AptosTokenUpdatePropertyCall { - collection, - name, - key, - type_, - value, - } => aptos_token_update_property_call(collection, name, key, type_, value), } } @@ -302,51 +171,6 @@ impl EntryFunctionCall { } } -pub fn aptos_token_add_property_call( - collection: Vec, - name: Vec, - key: Vec, - type_: Vec, - value: Vec, -) -> 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, 4, - ]), - ident_str!("aptos_token").to_owned(), - ), - ident_str!("add_property_call").to_owned(), - vec![], - vec![ - bcs::to_bytes(&collection).unwrap(), - bcs::to_bytes(&name).unwrap(), - bcs::to_bytes(&key).unwrap(), - bcs::to_bytes(&type_).unwrap(), - bcs::to_bytes(&value).unwrap(), - ], - )) -} - -pub fn aptos_token_burn_call(collection: Vec, name: Vec) -> 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, 4, - ]), - ident_str!("aptos_token").to_owned(), - ), - ident_str!("burn_call").to_owned(), - vec![], - vec![ - bcs::to_bytes(&collection).unwrap(), - bcs::to_bytes(&name).unwrap(), - ], - )) -} - /// Create a new collection pub fn aptos_token_create_collection( description: Vec, @@ -395,24 +219,6 @@ pub fn aptos_token_create_collection( )) } -pub fn aptos_token_freeze_transfer_call(collection: Vec, name: Vec) -> 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, 4, - ]), - ident_str!("aptos_token").to_owned(), - ), - ident_str!("freeze_transfer_call").to_owned(), - vec![], - vec![ - bcs::to_bytes(&collection).unwrap(), - bcs::to_bytes(&name).unwrap(), - ], - )) -} - /// With an existing collection, directly mint a viable token into the creators account. pub fn aptos_token_mint( collection: Vec, @@ -478,242 +284,8 @@ pub fn aptos_token_mint_soul_bound( ], )) } - -pub fn aptos_token_remove_property_call( - collection: Vec, - name: Vec, - key: Vec, -) -> 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, 4, - ]), - ident_str!("aptos_token").to_owned(), - ), - ident_str!("remove_property_call").to_owned(), - vec![], - vec![ - bcs::to_bytes(&collection).unwrap(), - bcs::to_bytes(&name).unwrap(), - bcs::to_bytes(&key).unwrap(), - ], - )) -} - -pub fn aptos_token_set_collection_description_call( - collection: Vec, - description: Vec, -) -> 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, 4, - ]), - ident_str!("aptos_token").to_owned(), - ), - ident_str!("set_collection_description_call").to_owned(), - vec![], - vec![ - bcs::to_bytes(&collection).unwrap(), - bcs::to_bytes(&description).unwrap(), - ], - )) -} - -pub fn aptos_token_set_collection_royalties_call( - collection: Vec, - royalty_numerator: u64, - royalty_denominator: u64, - payee_address: AccountAddress, -) -> 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, 4, - ]), - ident_str!("aptos_token").to_owned(), - ), - ident_str!("set_collection_royalties_call").to_owned(), - vec![], - vec![ - bcs::to_bytes(&collection).unwrap(), - bcs::to_bytes(&royalty_numerator).unwrap(), - bcs::to_bytes(&royalty_denominator).unwrap(), - bcs::to_bytes(&payee_address).unwrap(), - ], - )) -} - -pub fn aptos_token_set_collection_uri_call( - collection: Vec, - uri: Vec, -) -> 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, 4, - ]), - ident_str!("aptos_token").to_owned(), - ), - ident_str!("set_collection_uri_call").to_owned(), - vec![], - vec![ - bcs::to_bytes(&collection).unwrap(), - bcs::to_bytes(&uri).unwrap(), - ], - )) -} - -pub fn aptos_token_set_description_call( - collection: Vec, - name: Vec, - description: Vec, -) -> 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, 4, - ]), - ident_str!("aptos_token").to_owned(), - ), - ident_str!("set_description_call").to_owned(), - vec![], - vec![ - bcs::to_bytes(&collection).unwrap(), - bcs::to_bytes(&name).unwrap(), - bcs::to_bytes(&description).unwrap(), - ], - )) -} - -pub fn aptos_token_set_name_call( - collection: Vec, - original_name: Vec, - new_name: Vec, -) -> 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, 4, - ]), - ident_str!("aptos_token").to_owned(), - ), - ident_str!("set_name_call").to_owned(), - vec![], - vec![ - bcs::to_bytes(&collection).unwrap(), - bcs::to_bytes(&original_name).unwrap(), - bcs::to_bytes(&new_name).unwrap(), - ], - )) -} - -pub fn aptos_token_set_uri_call( - collection: Vec, - name: Vec, - uri: Vec, -) -> 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, 4, - ]), - ident_str!("aptos_token").to_owned(), - ), - ident_str!("set_uri_call").to_owned(), - vec![], - vec![ - bcs::to_bytes(&collection).unwrap(), - bcs::to_bytes(&name).unwrap(), - bcs::to_bytes(&uri).unwrap(), - ], - )) -} - -pub fn aptos_token_unfreeze_transfer_call( - collection: Vec, - name: Vec, -) -> 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, 4, - ]), - ident_str!("aptos_token").to_owned(), - ), - ident_str!("unfreeze_transfer_call").to_owned(), - vec![], - vec![ - bcs::to_bytes(&collection).unwrap(), - bcs::to_bytes(&name).unwrap(), - ], - )) -} - -pub fn aptos_token_update_property_call( - collection: Vec, - name: Vec, - key: Vec, - type_: Vec, - value: Vec, -) -> 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, 4, - ]), - ident_str!("aptos_token").to_owned(), - ), - ident_str!("update_property_call").to_owned(), - vec![], - vec![ - bcs::to_bytes(&collection).unwrap(), - bcs::to_bytes(&name).unwrap(), - bcs::to_bytes(&key).unwrap(), - bcs::to_bytes(&type_).unwrap(), - bcs::to_bytes(&value).unwrap(), - ], - )) -} mod decoder { use super::*; - pub fn aptos_token_add_property_call( - payload: &TransactionPayload, - ) -> Option { - if let TransactionPayload::EntryFunction(script) = payload { - Some(EntryFunctionCall::AptosTokenAddPropertyCall { - collection: bcs::from_bytes(script.args().get(0)?).ok()?, - name: bcs::from_bytes(script.args().get(1)?).ok()?, - key: bcs::from_bytes(script.args().get(2)?).ok()?, - type_: bcs::from_bytes(script.args().get(3)?).ok()?, - value: bcs::from_bytes(script.args().get(4)?).ok()?, - }) - } else { - None - } - } - - pub fn aptos_token_burn_call(payload: &TransactionPayload) -> Option { - if let TransactionPayload::EntryFunction(script) = payload { - Some(EntryFunctionCall::AptosTokenBurnCall { - collection: bcs::from_bytes(script.args().get(0)?).ok()?, - name: bcs::from_bytes(script.args().get(1)?).ok()?, - }) - } else { - None - } - } - pub fn aptos_token_create_collection( payload: &TransactionPayload, ) -> Option { @@ -740,19 +312,6 @@ mod decoder { } } - pub fn aptos_token_freeze_transfer_call( - payload: &TransactionPayload, - ) -> Option { - if let TransactionPayload::EntryFunction(script) = payload { - Some(EntryFunctionCall::AptosTokenFreezeTransferCall { - collection: bcs::from_bytes(script.args().get(0)?).ok()?, - name: bcs::from_bytes(script.args().get(1)?).ok()?, - }) - } else { - None - } - } - pub fn aptos_token_mint(payload: &TransactionPayload) -> Option { if let TransactionPayload::EntryFunction(script) = payload { Some(EntryFunctionCall::AptosTokenMint { @@ -785,128 +344,6 @@ mod decoder { None } } - - pub fn aptos_token_remove_property_call( - payload: &TransactionPayload, - ) -> Option { - if let TransactionPayload::EntryFunction(script) = payload { - Some(EntryFunctionCall::AptosTokenRemovePropertyCall { - collection: bcs::from_bytes(script.args().get(0)?).ok()?, - name: bcs::from_bytes(script.args().get(1)?).ok()?, - key: bcs::from_bytes(script.args().get(2)?).ok()?, - }) - } else { - None - } - } - - pub fn aptos_token_set_collection_description_call( - payload: &TransactionPayload, - ) -> Option { - if let TransactionPayload::EntryFunction(script) = payload { - Some(EntryFunctionCall::AptosTokenSetCollectionDescriptionCall { - collection: bcs::from_bytes(script.args().get(0)?).ok()?, - description: bcs::from_bytes(script.args().get(1)?).ok()?, - }) - } else { - None - } - } - - pub fn aptos_token_set_collection_royalties_call( - payload: &TransactionPayload, - ) -> Option { - if let TransactionPayload::EntryFunction(script) = payload { - Some(EntryFunctionCall::AptosTokenSetCollectionRoyaltiesCall { - collection: bcs::from_bytes(script.args().get(0)?).ok()?, - royalty_numerator: bcs::from_bytes(script.args().get(1)?).ok()?, - royalty_denominator: bcs::from_bytes(script.args().get(2)?).ok()?, - payee_address: bcs::from_bytes(script.args().get(3)?).ok()?, - }) - } else { - None - } - } - - pub fn aptos_token_set_collection_uri_call( - payload: &TransactionPayload, - ) -> Option { - if let TransactionPayload::EntryFunction(script) = payload { - Some(EntryFunctionCall::AptosTokenSetCollectionUriCall { - collection: bcs::from_bytes(script.args().get(0)?).ok()?, - uri: bcs::from_bytes(script.args().get(1)?).ok()?, - }) - } else { - None - } - } - - pub fn aptos_token_set_description_call( - payload: &TransactionPayload, - ) -> Option { - if let TransactionPayload::EntryFunction(script) = payload { - Some(EntryFunctionCall::AptosTokenSetDescriptionCall { - collection: bcs::from_bytes(script.args().get(0)?).ok()?, - name: bcs::from_bytes(script.args().get(1)?).ok()?, - description: bcs::from_bytes(script.args().get(2)?).ok()?, - }) - } else { - None - } - } - - pub fn aptos_token_set_name_call(payload: &TransactionPayload) -> Option { - if let TransactionPayload::EntryFunction(script) = payload { - Some(EntryFunctionCall::AptosTokenSetNameCall { - collection: bcs::from_bytes(script.args().get(0)?).ok()?, - original_name: bcs::from_bytes(script.args().get(1)?).ok()?, - new_name: bcs::from_bytes(script.args().get(2)?).ok()?, - }) - } else { - None - } - } - - pub fn aptos_token_set_uri_call(payload: &TransactionPayload) -> Option { - if let TransactionPayload::EntryFunction(script) = payload { - Some(EntryFunctionCall::AptosTokenSetUriCall { - collection: bcs::from_bytes(script.args().get(0)?).ok()?, - name: bcs::from_bytes(script.args().get(1)?).ok()?, - uri: bcs::from_bytes(script.args().get(2)?).ok()?, - }) - } else { - None - } - } - - pub fn aptos_token_unfreeze_transfer_call( - payload: &TransactionPayload, - ) -> Option { - if let TransactionPayload::EntryFunction(script) = payload { - Some(EntryFunctionCall::AptosTokenUnfreezeTransferCall { - collection: bcs::from_bytes(script.args().get(0)?).ok()?, - name: bcs::from_bytes(script.args().get(1)?).ok()?, - }) - } else { - None - } - } - - pub fn aptos_token_update_property_call( - payload: &TransactionPayload, - ) -> Option { - if let TransactionPayload::EntryFunction(script) = payload { - Some(EntryFunctionCall::AptosTokenUpdatePropertyCall { - collection: bcs::from_bytes(script.args().get(0)?).ok()?, - name: bcs::from_bytes(script.args().get(1)?).ok()?, - key: bcs::from_bytes(script.args().get(2)?).ok()?, - type_: bcs::from_bytes(script.args().get(3)?).ok()?, - value: bcs::from_bytes(script.args().get(4)?).ok()?, - }) - } else { - None - } - } } type EntryFunctionDecoderMap = std::collections::HashMap< @@ -921,22 +358,10 @@ type EntryFunctionDecoderMap = std::collections::HashMap< static SCRIPT_FUNCTION_DECODER_MAP: once_cell::sync::Lazy = once_cell::sync::Lazy::new(|| { let mut map: EntryFunctionDecoderMap = std::collections::HashMap::new(); - map.insert( - "aptos_token_add_property_call".to_string(), - Box::new(decoder::aptos_token_add_property_call), - ); - map.insert( - "aptos_token_burn_call".to_string(), - Box::new(decoder::aptos_token_burn_call), - ); map.insert( "aptos_token_create_collection".to_string(), Box::new(decoder::aptos_token_create_collection), ); - map.insert( - "aptos_token_freeze_transfer_call".to_string(), - Box::new(decoder::aptos_token_freeze_transfer_call), - ); map.insert( "aptos_token_mint".to_string(), Box::new(decoder::aptos_token_mint), @@ -945,41 +370,5 @@ static SCRIPT_FUNCTION_DECODER_MAP: once_cell::sync::Lazy Date: Sat, 25 Mar 2023 20:50:16 -0700 Subject: [PATCH 09/13] [genesis] enable new input type parsing for devnet --- .../aptos-release-builder/data/release.yaml | 1 + aptos-move/e2e-move-tests/src/harness.rs | 15 +++ .../e2e-move-tests/src/tests/string_args.rs | 127 ++++++------------ aptos-move/vm-genesis/src/lib.rs | 1 + 4 files changed, 58 insertions(+), 86 deletions(-) diff --git a/aptos-move/aptos-release-builder/data/release.yaml b/aptos-move/aptos-release-builder/data/release.yaml index cd956ac7baf75..4b0112c574ede 100644 --- a/aptos-move/aptos-release-builder/data/release.yaml +++ b/aptos-move/aptos-release-builder/data/release.yaml @@ -20,6 +20,7 @@ update_sequence: - multisig_accounts - delegation_pools - ed25519_pubkey_validate_return_false_wrong_length + - struct_constructors disabled: [] - Consensus: V1: diff --git a/aptos-move/e2e-move-tests/src/harness.rs b/aptos-move/e2e-move-tests/src/harness.rs index 42cb2009fb2a4..c17e42f9b58c8 100644 --- a/aptos-move/e2e-move-tests/src/harness.rs +++ b/aptos-move/e2e-move-tests/src/harness.rs @@ -615,3 +615,18 @@ macro_rules! assert_vm_status { ); }}; } + +#[macro_export] +macro_rules! assert_move_abort { + ($s:expr, $c:ident) => {{ + use aptos_types::transaction::*; + assert!(match $s { + TransactionStatus::Keep(ExecutionStatus::MoveAbort { + location: _, + code: _, + info, + }) => info == $c, + _ => false, + }); + }}; +} diff --git a/aptos-move/e2e-move-tests/src/tests/string_args.rs b/aptos-move/e2e-move-tests/src/tests/string_args.rs index e7d7b15177b32..0910f2cf82aec 100644 --- a/aptos-move/e2e-move-tests/src/tests/string_args.rs +++ b/aptos-move/e2e-move-tests/src/tests/string_args.rs @@ -1,8 +1,11 @@ // Copyright © Aptos Foundation // SPDX-License-Identifier: Apache-2.0 -use crate::{assert_success, assert_vm_status, tests::common, MoveHarness}; -use aptos_types::account_address::AccountAddress; +use crate::{assert_move_abort, assert_success, assert_vm_status, tests::common, MoveHarness}; +use aptos_types::{ + account_address::AccountAddress, + transaction::{AbortInfo, TransactionStatus}, +}; use move_core_types::{ identifier::Identifier, language_storage::{StructTag, TypeTag}, @@ -62,11 +65,27 @@ fn success_generic(ty_args: Vec, tests: Vec<(&str, Vec<(Vec>, & } } -fn fail(tests: Vec<(&str, Vec>, StatusCode)>) { +fn deserialization_failure() -> impl Fn(TransactionStatus) { + let status_code = StatusCode::FAILED_TO_DESERIALIZE_ARGUMENT; + move |txn_status| assert_vm_status!(txn_status, status_code) +} + +fn abort_info() -> impl Fn(TransactionStatus) { + let abort_info = Some(AbortInfo { + reason_name: "EINVALID_UTF8".to_string(), + description: "An invalid UTF8 encoding.".to_string(), + }); + move |txn_status| assert_move_abort!(txn_status, abort_info) +} + +fn fail(tests: Vec<(&str, Vec>, impl Fn(TransactionStatus))>) { fail_generic(vec![], tests) } -fn fail_generic(ty_args: Vec, tests: Vec<(&str, Vec>, StatusCode)>) { +fn fail_generic( + ty_args: Vec, + tests: Vec<(&str, Vec>, impl Fn(TransactionStatus))>, +) { let mut h = MoveHarness::new(); // Load the code @@ -81,7 +100,7 @@ fn fail_generic(ty_args: Vec, tests: Vec<(&str, Vec>, StatusCod for (entry, args, err) in tests { // Now send hi transaction, after that resource should exist and carry value let status = h.run_entry_function(&acc, str::parse(entry).unwrap(), ty_args.clone(), args); - assert_vm_status!(status, err); + err(status); } } @@ -289,38 +308,22 @@ fn string_args_bad_utf8() { // simple strings let args = vec![bcs::to_bytes(&vec![0xF0u8, 0x28u8, 0x8Cu8, 0xBCu8]).unwrap()]; - tests.push(( - "0xcafe::test::hi", - args, - StatusCode::FAILED_TO_DESERIALIZE_ARGUMENT, - )); + tests.push(("0xcafe::test::hi", args, abort_info())); let args = vec![bcs::to_bytes(&vec![0xC3u8, 0x28u8]).unwrap()]; - tests.push(( - "0xcafe::test::hi", - args, - StatusCode::FAILED_TO_DESERIALIZE_ARGUMENT, - )); + tests.push(("0xcafe::test::hi", args, abort_info())); // vector of strings let bad = vec![0xC3u8, 0x28u8]; let s_vec = vec![&bad[..], "hello".as_bytes(), "world".as_bytes()]; let i = 0u64; let args = vec![bcs::to_bytes(&s_vec).unwrap(), bcs::to_bytes(&i).unwrap()]; - tests.push(( - "0xcafe::test::str_vec", - args, - StatusCode::FAILED_TO_DESERIALIZE_ARGUMENT, - )); + tests.push(("0xcafe::test::str_vec", args, abort_info())); let bad = vec![0xC3u8, 0x28u8]; let s_vec = vec![&bad[..], "hello".as_bytes(), "world".as_bytes()]; let args = vec![bcs::to_bytes(&s_vec).unwrap(), bcs::to_bytes(&i).unwrap()]; - tests.push(( - "0xcafe::test::str_vec", - args, - StatusCode::FAILED_TO_DESERIALIZE_ARGUMENT, - )); + tests.push(("0xcafe::test::str_vec", args, abort_info())); // vector of vector of strings let i = 0u64; @@ -345,11 +348,7 @@ fn string_args_bad_utf8() { bcs::to_bytes(&i).unwrap(), bcs::to_bytes(&j).unwrap(), ]; - tests.push(( - "0xcafe::test::str_vec_vec", - args, - StatusCode::FAILED_TO_DESERIALIZE_ARGUMENT, - )); + tests.push(("0xcafe::test::str_vec_vec", args, abort_info())); let bad = vec![0xF0u8, 0x28u8, 0x8Cu8, 0x28u8]; let s_vec = vec![ @@ -370,11 +369,7 @@ fn string_args_bad_utf8() { bcs::to_bytes(&i).unwrap(), bcs::to_bytes(&j).unwrap(), ]; - tests.push(( - "0xcafe::test::str_vec_vec", - args, - StatusCode::FAILED_TO_DESERIALIZE_ARGUMENT, - )); + tests.push(("0xcafe::test::str_vec_vec", args, abort_info())); let bad = vec![0x60u8, 0xFFu8]; let s_vec = vec![ @@ -395,11 +390,7 @@ fn string_args_bad_utf8() { bcs::to_bytes(&i).unwrap(), bcs::to_bytes(&j).unwrap(), ]; - tests.push(( - "0xcafe::test::str_vec_vec", - args, - StatusCode::FAILED_TO_DESERIALIZE_ARGUMENT, - )); + tests.push(("0xcafe::test::str_vec_vec", args, abort_info())); fail(tests); } @@ -421,7 +412,7 @@ fn string_args_chopped() { fail(vec![( "0xcafe::test::str_vec", args, - StatusCode::FAILED_TO_DESERIALIZE_ARGUMENT, + deserialization_failure(), )]); i /= 2; } @@ -437,20 +428,12 @@ fn string_args_bad_length() { // length over max size let mut args = bcs::to_bytes(&vec![0x30u8; 100000]).unwrap(); args.truncate(20); - tests.push(( - "0xcafe::test::hi", - vec![args], - StatusCode::FAILED_TO_DESERIALIZE_ARGUMENT, - )); + tests.push(("0xcafe::test::hi", vec![args], deserialization_failure())); // length in size but input chopped let mut args = bcs::to_bytes(&vec![0x30u8; 30000]).unwrap(); args.truncate(300); - tests.push(( - "0xcafe::test::hi", - vec![args], - StatusCode::FAILED_TO_DESERIALIZE_ARGUMENT, - )); + tests.push(("0xcafe::test::hi", vec![args], deserialization_failure())); // vector of strings @@ -461,11 +444,7 @@ fn string_args_bad_length() { bcs_vec.truncate(200); let i = 0u64; let args = vec![bcs_vec, bcs::to_bytes(&i).unwrap()]; - tests.push(( - "0xcafe::test::str_vec", - args, - StatusCode::FAILED_TO_DESERIALIZE_ARGUMENT, - )); + tests.push(("0xcafe::test::str_vec", args, deserialization_failure())); // length over max size after 2 big-ish strings let bad = vec![0x30u8; 100000]; @@ -474,11 +453,7 @@ fn string_args_bad_length() { let mut bcs_vec = bcs::to_bytes(&s_vec).unwrap(); bcs_vec.truncate(30000); let args = vec![bcs_vec, bcs::to_bytes(&i).unwrap()]; - tests.push(( - "0xcafe::test::str_vec", - args, - StatusCode::FAILED_TO_DESERIALIZE_ARGUMENT, - )); + tests.push(("0xcafe::test::str_vec", args, deserialization_failure())); // length in size but input chopped let big = vec![0x30u8; 10000]; @@ -486,11 +461,7 @@ fn string_args_bad_length() { let mut bcs_vec = bcs::to_bytes(&s_vec).unwrap(); bcs_vec.truncate(20000); let args = vec![bcs_vec, bcs::to_bytes(&i).unwrap()]; - tests.push(( - "0xcafe::test::str_vec", - args, - StatusCode::FAILED_TO_DESERIALIZE_ARGUMENT, - )); + tests.push(("0xcafe::test::str_vec", args, deserialization_failure())); // vector of vector of strings @@ -518,11 +489,7 @@ fn string_args_bad_length() { bcs::to_bytes(&i).unwrap(), bcs::to_bytes(&j).unwrap(), ]; - tests.push(( - "0xcafe::test::str_vec_vec", - args, - StatusCode::FAILED_TO_DESERIALIZE_ARGUMENT, - )); + tests.push(("0xcafe::test::str_vec_vec", args, deserialization_failure())); let bad = vec![0x30u8; 10000]; let s_vec = vec![ @@ -545,11 +512,7 @@ fn string_args_bad_length() { bcs::to_bytes(&i).unwrap(), bcs::to_bytes(&j).unwrap(), ]; - tests.push(( - "0xcafe::test::str_vec_vec", - args, - StatusCode::FAILED_TO_DESERIALIZE_ARGUMENT, - )); + tests.push(("0xcafe::test::str_vec_vec", args, deserialization_failure())); let bad = vec![0x30u8; 100000]; let s_vec = vec![ @@ -572,11 +535,7 @@ fn string_args_bad_length() { bcs::to_bytes(&i).unwrap(), bcs::to_bytes(&j).unwrap(), ]; - tests.push(( - "0xcafe::test::str_vec_vec", - args, - StatusCode::FAILED_TO_DESERIALIZE_ARGUMENT, - )); + tests.push(("0xcafe::test::str_vec_vec", args, deserialization_failure())); // length over max size with 0 length strings let s_vec = vec![vec!["".as_bytes(); 3]; 100000]; @@ -603,11 +562,7 @@ fn string_args_bad_length() { bcs::to_bytes(&j).unwrap(), ]; - tests.push(( - "0xcafe::test::str_vec_vec", - args, - StatusCode::FAILED_TO_DESERIALIZE_ARGUMENT, - )); + tests.push(("0xcafe::test::str_vec_vec", args, deserialization_failure())); fail(tests); } diff --git a/aptos-move/vm-genesis/src/lib.rs b/aptos-move/vm-genesis/src/lib.rs index 32dce2d4ee25b..518a90db83f4f 100644 --- a/aptos-move/vm-genesis/src/lib.rs +++ b/aptos-move/vm-genesis/src/lib.rs @@ -420,6 +420,7 @@ pub fn default_features() -> Vec { FeatureFlag::MULTISIG_ACCOUNTS, FeatureFlag::DELEGATION_POOLS, FeatureFlag::ED25519_PUBKEY_VALIDATE_RETURN_FALSE_WRONG_LENGTH, + FeatureFlag::STRUCT_CONSTRUCTORS, ] } From 8fd440b359d6f1401d1256b7dcf004f0bd9baf92 Mon Sep 17 00:00:00 2001 From: David Wolinsky Date: Sat, 25 Mar 2023 20:55:15 -0700 Subject: [PATCH 10/13] [framework] add view attribute to aptos_token readers --- .../framework/aptos-token-objects/sources/aptos_token.move | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/aptos-move/framework/aptos-token-objects/sources/aptos_token.move b/aptos-move/framework/aptos-token-objects/sources/aptos_token.move index 24b8800f54dcc..92813f439f5c4 100644 --- a/aptos-move/framework/aptos-token-objects/sources/aptos_token.move +++ b/aptos-move/framework/aptos-token-objects/sources/aptos_token.move @@ -256,27 +256,33 @@ module aptos_token_objects::aptos_token { borrow_global(token_address) } + #[view] public fun are_properties_mutable(token: Object): bool acquires AptosCollection { let collection = token::collection_object(token); borrow_collection(&collection).mutable_token_properties } + #[view] public fun is_burnable(token: Object): bool acquires AptosToken { option::is_some(&borrow(&token).burn_ref) } + #[view] public fun is_freezable_by_creator(token: Object): bool acquires AptosCollection { are_collection_tokens_freezable(token::collection_object(token)) } + #[view] public fun is_mutable_description(token: Object): bool acquires AptosCollection { is_mutable_collection_token_description(token::collection_object(token)) } + #[view] public fun is_mutable_name(token: Object): bool acquires AptosCollection { is_mutable_collection_token_name(token::collection_object(token)) } + #[view] public fun is_mutable_uri(token: Object): bool acquires AptosCollection { is_mutable_collection_token_uri(token::collection_object(token)) } From 8925e65d076a26c53fbb1928f0f9923cbbc71d4b Mon Sep 17 00:00:00 2001 From: David Wolinsky Date: Sat, 25 Mar 2023 09:58:32 -0700 Subject: [PATCH 11/13] [python] add support for generating account addresses * Named Objects * Named tokens * Named collections * Moved auth key generation back into the account_address module from ed25519 for multi-ed as that's where it was defined for other frameworks --- .../python/sdk/aptos_sdk/account_address.py | 106 +++++++++++++++++- .../python/sdk/aptos_sdk/authenticator.py | 4 +- ecosystem/python/sdk/aptos_sdk/ed25519.py | 62 ++++------ ecosystem/python/sdk/examples/multisig.py | 14 +-- types/src/account_address.rs | 9 +- 5 files changed, 140 insertions(+), 55 deletions(-) diff --git a/ecosystem/python/sdk/aptos_sdk/account_address.py b/ecosystem/python/sdk/aptos_sdk/account_address.py index 4ca2049f52239..db49df3675d36 100644 --- a/ecosystem/python/sdk/aptos_sdk/account_address.py +++ b/ecosystem/python/sdk/aptos_sdk/account_address.py @@ -4,12 +4,20 @@ from __future__ import annotations import hashlib -from typing import List +import unittest from . import ed25519 from .bcs import Deserializer, Serializer +class AuthKeyScheme: + Ed25519: bytes = b"\x00" + MultiEd25519: bytes = b"\x01" + DeriveObjectAddressFromGuid: bytes = b"\xFD" + DeriveObjectAddressFromSeed: bytes = b"\xFE" + DeriveResourceAccountAddress: bytes = b"\xFF" + + class AccountAddress: address: bytes LENGTH: int = 32 @@ -47,15 +55,48 @@ def from_hex(address: str) -> AccountAddress: @staticmethod def from_key(key: ed25519.PublicKey) -> AccountAddress: hasher = hashlib.sha3_256() - hasher.update(key.key.encode() + b"\x00") + hasher.update(key.key.encode()) + hasher.update(AuthKeyScheme.Ed25519) + return AccountAddress(hasher.digest()) + + @staticmethod + def from_multi_ed25519(keys: ed25519.MultiPublicKey) -> AccountAddress: + hasher = hashlib.sha3_256() + hasher.update(keys.to_bytes()) + hasher.update(AuthKeyScheme.MultiEd25519) + return AccountAddress(hasher.digest()) + + @staticmethod + def for_resource_account(creator: AccountAddress, seed: bytes) -> AccountAddress: + hasher = hashlib.sha3_256() + hasher.update(creator.address) + hasher.update(seed) + hasher.update(AuthKeyScheme.DeriveResourceAccountAddress) return AccountAddress(hasher.digest()) @staticmethod - def from_multisig_schema( - keys: List[ed25519.PublicKey], threshold: int + def for_named_object(creator: AccountAddress, seed: bytes) -> AccountAddress: + hasher = hashlib.sha3_256() + hasher.update(creator.address) + hasher.update(seed) + hasher.update(AuthKeyScheme.DeriveObjectAddressFromSeed) + return AccountAddress(hasher.digest()) + + @staticmethod + def for_named_token( + creator: AccountAddress, collection_name: str, token_name: str ) -> AccountAddress: - multisig_public_key = ed25519.MultiEd25519PublicKey(keys, threshold) - return AccountAddress(multisig_public_key.auth_key()) + collection_bytes = collection_name.encode() + token_bytes = token_name.encode() + return AccountAddress.for_named_object( + creator, collection_bytes + b"::" + token_bytes + ) + + @staticmethod + def for_named_collection( + creator: AccountAddress, collection_name: str + ) -> AccountAddress: + return AccountAddress.for_named_object(creator, collection_name.encode()) @staticmethod def deserialize(deserializer: Deserializer) -> AccountAddress: @@ -63,3 +104,56 @@ def deserialize(deserializer: Deserializer) -> AccountAddress: def serialize(self, serializer: Serializer): serializer.fixed_bytes(self.address) + + +class Test(unittest.TestCase): + def test_multi_ed25519(self): + private_key_1 = ed25519.PrivateKey.from_hex( + "4e5e3be60f4bbd5e98d086d932f3ce779ff4b58da99bf9e5241ae1212a29e5fe" + ) + private_key_2 = ed25519.PrivateKey.from_hex( + "1e70e49b78f976644e2c51754a2f049d3ff041869c669523ba95b172c7329901" + ) + multisig_public_key = ed25519.MultiPublicKey( + [private_key_1.public_key(), private_key_2.public_key()], 1 + ) + + expected = AccountAddress.from_hex( + "835bb8c5ee481062946b18bbb3b42a40b998d6bf5316ca63834c959dc739acf0" + ) + actual = AccountAddress.from_multi_ed25519(multisig_public_key) + self.assertEqual(actual, expected) + + def test_resource_account(self): + base_address = AccountAddress.from_hex("b0b") + expected = AccountAddress.from_hex( + "ee89f8c763c27f9d942d496c1a0dcf32d5eacfe78416f9486b8db66155b163b0" + ) + actual = AccountAddress.for_resource_account(base_address, b"\x0b\x00\x0b") + self.assertEqual(actual, expected) + + def test_named_object(self): + base_address = AccountAddress.from_hex("b0b") + expected = AccountAddress.from_hex( + "f417184602a828a3819edf5e36285ebef5e4db1ba36270be580d6fd2d7bcc321" + ) + actual = AccountAddress.for_named_object(base_address, b"bob's collection") + self.assertEqual(actual, expected) + + def test_collection(self): + base_address = AccountAddress.from_hex("b0b") + expected = AccountAddress.from_hex( + "f417184602a828a3819edf5e36285ebef5e4db1ba36270be580d6fd2d7bcc321" + ) + actual = AccountAddress.for_named_collection(base_address, "bob's collection") + self.assertEqual(actual, expected) + + def test_token(self): + base_address = AccountAddress.from_hex("b0b") + expected = AccountAddress.from_hex( + "e20d1f22a5400ba7be0f515b7cbd00edc42dbcc31acc01e31128b2b5ddb3c56e" + ) + actual = AccountAddress.for_named_token( + base_address, "bob's collection", "bob's token" + ) + self.assertEqual(actual, expected) diff --git a/ecosystem/python/sdk/aptos_sdk/authenticator.py b/ecosystem/python/sdk/aptos_sdk/authenticator.py index ca83870ce0677..89998eb1e1c13 100644 --- a/ecosystem/python/sdk/aptos_sdk/authenticator.py +++ b/ecosystem/python/sdk/aptos_sdk/authenticator.py @@ -146,8 +146,8 @@ def serialize(self, serializer: Serializer): class MultiEd25519Authenticator: - public_key: ed25519.MultiEd25519PublicKey - signature: ed25519.MultiEd25519Signature + public_key: ed25519.MultiPublicKey + signature: ed25519.MultiSignature def __init__(self, public_key, signature): self.public_key = public_key diff --git a/ecosystem/python/sdk/aptos_sdk/ed25519.py b/ecosystem/python/sdk/aptos_sdk/ed25519.py index c8fa3dd346439..2d3bc0e552cda 100644 --- a/ecosystem/python/sdk/aptos_sdk/ed25519.py +++ b/ecosystem/python/sdk/aptos_sdk/ed25519.py @@ -3,7 +3,6 @@ from __future__ import annotations -import hashlib import unittest from typing import List, Tuple @@ -94,7 +93,7 @@ def serialize(self, serializer: Serializer): serializer.to_bytes(self.key.encode()) -class MultiEd25519PublicKey: +class MultiPublicKey: keys: List[PublicKey] threshold: int @@ -116,11 +115,6 @@ def __init__(self, keys: List[PublicKey], threshold: int, checked=True): def __str__(self) -> str: return f"{self.threshold}-of-{len(self.keys)} Multi-Ed25519 public key" - def auth_key(self) -> bytes: - hasher = hashlib.sha3_256() - hasher.update(self.to_bytes() + b"\x01") - return hasher.digest() - def to_bytes(self) -> bytes: concatenated_keys = bytes() for key in self.keys: @@ -128,11 +122,11 @@ def to_bytes(self) -> bytes: return concatenated_keys + bytes([self.threshold]) @staticmethod - def from_bytes(key: bytes) -> MultiEd25519PublicKey: + def from_bytes(key: bytes) -> MultiPublicKey: # Get key count and threshold limits. - min_keys = MultiEd25519PublicKey.MIN_KEYS - max_keys = MultiEd25519PublicKey.MAX_KEYS - min_threshold = MultiEd25519PublicKey.MIN_THRESHOLD + min_keys = MultiPublicKey.MIN_KEYS + max_keys = MultiPublicKey.MAX_KEYS + min_threshold = MultiPublicKey.MIN_THRESHOLD # Get number of signers. n_signers = int(len(key) / PublicKey.LENGTH) assert ( @@ -149,7 +143,7 @@ def from_bytes(key: bytes) -> MultiEd25519PublicKey: start_byte = i * PublicKey.LENGTH end_byte = (i + 1) * PublicKey.LENGTH keys.append(PublicKey(VerifyKey(key[start_byte:end_byte]))) - return MultiEd25519PublicKey(keys, threshold) + return MultiPublicKey(keys, threshold) def serialize(self, serializer: Serializer): serializer.to_bytes(self.to_bytes()) @@ -186,13 +180,13 @@ def serialize(self, serializer: Serializer): serializer.to_bytes(self.signature) -class MultiEd25519Signature: +class MultiSignature: signatures: List[Signature] bitmap: bytes def __init__( self, - public_key: MultiEd25519PublicKey, + public_key: MultiPublicKey, signatures_map: List[Tuple[PublicKey, Signature]], ): self.signatures = list() @@ -261,16 +255,9 @@ def test_multisig(self): "1e70e49b78f976644e2c51754a2f049d3ff041869c669523ba95b172c7329901" ) # Generate multisig public key with threshold of 1. - multisig_public_key = MultiEd25519PublicKey( + multisig_public_key = MultiPublicKey( [private_key_1.public_key(), private_key_2.public_key()], 1 ) - # Check expected authentication key. - expected_authentication_key = ( - "835bb8c5ee481062946b18bbb3b42a40b998d6bf5316ca63834c959dc739acf0" - ) - self.assertEqual( - multisig_public_key.auth_key().hex(), expected_authentication_key - ) # Get public key BCS representation. serializer = Serializer() multisig_public_key.serialize(serializer) @@ -284,7 +271,7 @@ def test_multisig(self): # Get public key bytes representation. public_key_bytes = multisig_public_key.to_bytes() # Convert back to multisig class instance from bytes. - multisig_public_key = MultiEd25519PublicKey.from_bytes(public_key_bytes) + multisig_public_key = MultiPublicKey.from_bytes(public_key_bytes) # Get public key BCS representation. serializer = Serializer() multisig_public_key.serialize(serializer) @@ -294,7 +281,7 @@ def test_multisig(self): # Have one signer sign arbitrary message. signature = private_key_2.sign(b"multisig") # Compose multisig signature. - multisig_signature = MultiEd25519Signature( + multisig_signature = MultiSignature( multisig_public_key, [(private_key_2.public_key(), signature)] ) # Get signature BCS representation. @@ -312,46 +299,43 @@ def test_multisig(self): def test_multisig_range_checks(self): # Generate public keys. keys = [ - PrivateKey.random().public_key() - for x in range(MultiEd25519PublicKey.MAX_KEYS + 1) + PrivateKey.random().public_key() for x in range(MultiPublicKey.MAX_KEYS + 1) ] # Verify failure for initializing multisig instance with too few keys. with self.assertRaisesRegex(AssertionError, "Must have between 2 and 32 keys."): - MultiEd25519PublicKey([keys[0]], 1) + MultiPublicKey([keys[0]], 1) # Verify failure for initializing multisig instance with too many keys. with self.assertRaisesRegex(AssertionError, "Must have between 2 and 32 keys."): - MultiEd25519PublicKey(keys, 1) + MultiPublicKey(keys, 1) # Verify failure for initializing multisig instance with small threshold. with self.assertRaisesRegex( AssertionError, "Threshold must be between 1 and 4." ): - MultiEd25519PublicKey(keys[0:4], 0) + MultiPublicKey(keys[0:4], 0) # Verify failure for initializing multisig instance with large threshold. with self.assertRaisesRegex( AssertionError, "Threshold must be between 1 and 4." ): - MultiEd25519PublicKey(keys[0:4], 5) + MultiPublicKey(keys[0:4], 5) # Verify failure for initializing from bytes with too few keys. with self.assertRaisesRegex(AssertionError, "Must have between 2 and 32 keys."): - MultiEd25519PublicKey.from_bytes( - MultiEd25519PublicKey([keys[0]], 1, checked=False).to_bytes() + MultiPublicKey.from_bytes( + MultiPublicKey([keys[0]], 1, checked=False).to_bytes() ) # Verify failure for initializing from bytes with too many keys. with self.assertRaisesRegex(AssertionError, "Must have between 2 and 32 keys."): - MultiEd25519PublicKey.from_bytes( - MultiEd25519PublicKey(keys, 1, checked=False).to_bytes() - ) + MultiPublicKey.from_bytes(MultiPublicKey(keys, 1, checked=False).to_bytes()) # Verify failure for initializing from bytes with small threshold. with self.assertRaisesRegex( AssertionError, "Threshold must be between 1 and 4." ): - MultiEd25519PublicKey.from_bytes( - MultiEd25519PublicKey(keys[0:4], 0, checked=False).to_bytes() + MultiPublicKey.from_bytes( + MultiPublicKey(keys[0:4], 0, checked=False).to_bytes() ) # Verify failure for initializing from bytes with large threshold. with self.assertRaisesRegex( AssertionError, "Threshold must be between 1 and 4." ): - MultiEd25519PublicKey.from_bytes( - MultiEd25519PublicKey(keys[0:4], 5, checked=False).to_bytes() + MultiPublicKey.from_bytes( + MultiPublicKey(keys[0:4], 5, checked=False).to_bytes() ) diff --git a/ecosystem/python/sdk/examples/multisig.py b/ecosystem/python/sdk/examples/multisig.py index 953fcf3acc6a0..e5d4b78032b74 100644 --- a/ecosystem/python/sdk/examples/multisig.py +++ b/ecosystem/python/sdk/examples/multisig.py @@ -6,7 +6,7 @@ from aptos_sdk.authenticator import Authenticator, MultiEd25519Authenticator from aptos_sdk.bcs import Serializer from aptos_sdk.client import FaucetClient, RestClient -from aptos_sdk.ed25519 import MultiEd25519PublicKey, MultiEd25519Signature +from aptos_sdk.ed25519 import MultiPublicKey, MultiSignature from aptos_sdk.transactions import (EntryFunction, RawTransaction, Script, ScriptArgument, SignedTransaction, TransactionArgument, TransactionPayload) @@ -49,7 +49,7 @@ def wait(): # :!:>section_2 threshold = 2 - multisig_public_key = MultiEd25519PublicKey( + multisig_public_key = MultiPublicKey( [alice.public_key(), bob.public_key(), chad.public_key()], threshold ) @@ -129,7 +129,7 @@ def wait(): (bob.public_key(), bob_signature), ] - multisig_signature = MultiEd25519Signature(multisig_public_key, sig_map) + multisig_signature = MultiSignature(multisig_public_key, sig_map) authenticator = Authenticator( MultiEd25519Authenticator(multisig_public_key, multisig_signature) @@ -197,7 +197,7 @@ def wait(): cap_rotate_key = deedee.sign(rotation_proof_challenge_bcs).data() - cap_update_table = MultiEd25519Signature( + cap_update_table = MultiSignature( multisig_public_key, [ (bob.public_key(), bob.sign(rotation_proof_challenge_bcs)), @@ -309,7 +309,7 @@ def wait(): (chad.public_key(), chad_signature), ] - multisig_signature = MultiEd25519Signature(multisig_public_key, sig_map) + multisig_signature = MultiSignature(multisig_public_key, sig_map) authenticator = Authenticator( MultiEd25519Authenticator(multisig_public_key, multisig_signature) @@ -392,7 +392,7 @@ def wait(): (chad.public_key(), chad_signature), ] - multisig_signature = MultiEd25519Signature(multisig_public_key, sig_map) + multisig_signature = MultiSignature(multisig_public_key, sig_map) authenticator = Authenticator( MultiEd25519Authenticator(multisig_public_key, multisig_signature) @@ -449,7 +449,7 @@ def wait(): (bob.public_key(), bob_signature), ] - multisig_signature = MultiEd25519Signature(multisig_public_key, sig_map) + multisig_signature = MultiSignature(multisig_public_key, sig_map) authenticator = Authenticator( MultiEd25519Authenticator(multisig_public_key, multisig_signature) diff --git a/types/src/account_address.rs b/types/src/account_address.rs index 3ff3b6004e8f5..599708507db75 100644 --- a/types/src/account_address.rs +++ b/types/src/account_address.rs @@ -284,6 +284,13 @@ mod test { "{:?}", super::create_token_address(address, "bob's collection", "bob's token") ); - // println!("{:?}", create_object_address(address, guid); + println!( + "{:?}", + super::create_collection_address(address, "bob's collection") + ); + println!( + "{:?}", + super::create_resource_address(address, &[0x0B, 0x00, 0x0B]) + ); } } From 3fa430ea40bea3b8ad55d02fca80a723c31c636f Mon Sep 17 00:00:00 2001 From: David Wolinsky Date: Sat, 25 Mar 2023 21:08:07 -0700 Subject: [PATCH 12/13] [python] add aptos token client * this validates much of the token objects code * demonstrates a means to read objects efficiently using python * how to perform property type operations * read from property types * how to tie your shoes --- .../sdk/aptos_sdk/aptos_token_client.py | 574 ++++++++++++++++++ .../python/sdk/aptos_sdk/async_client.py | 32 + .../python/sdk/examples/async-aptos-token.py | 116 ++++ 3 files changed, 722 insertions(+) create mode 100644 ecosystem/python/sdk/aptos_sdk/aptos_token_client.py create mode 100644 ecosystem/python/sdk/examples/async-aptos-token.py diff --git a/ecosystem/python/sdk/aptos_sdk/aptos_token_client.py b/ecosystem/python/sdk/aptos_sdk/aptos_token_client.py new file mode 100644 index 0000000000000..0efb0036acb26 --- /dev/null +++ b/ecosystem/python/sdk/aptos_sdk/aptos_token_client.py @@ -0,0 +1,574 @@ +# Copyright © Aptos Foundation +# SPDX-License-Identifier: Apache-2.0 + +from __future__ import annotations + +from typing import Any, List, Optional, Tuple + +from .account import Account +from .account_address import AccountAddress +from .async_client import RestClient +from .bcs import Deserializer, Serializer +from .transactions import (EntryFunction, TransactionArgument, + TransactionPayload) +from .type_tag import StructTag, TypeTag + + +class Object: + + allow_ungated_transfer: bool + owner: AccountAddress + + struct_tag: str = "0x1::object::ObjectCore" + + def __init__(self, allow_ungated_transfer, owner): + self.allow_ungated_transfer = allow_ungated_transfer + self.owner = owner + + @staticmethod + def parse(resource: dict[str, Any]) -> Object: + return Object( + resource["allow_ungated_transfer"], + AccountAddress.from_hex(resource["owner"]), + ) + + def __str__(self) -> str: + return f"Object[allow_ungated_transfer: {self.allow_ungated_transfer}, owner: {self.owner}]" + + +class Collection: + + creator: AccountAddress + description: str + name: str + uri: str + + struct_tag: str = "0x4::collection::Collection" + + def __init__(self, creator, description, name, uri): + self.creator = creator + self.description = description + self.name = name + self.uri = uri + + def __str__(self) -> str: + return f"AccountAddress[creator: {self.creator}, description: {self.description}, name: {self.name}, ur: {self.uri}]" + + @staticmethod + def parse(resource: dict[str, Any]) -> Collection: + return Collection( + AccountAddress.from_hex(resource["creator"]), + resource["description"], + resource["name"], + resource["uri"], + ) + + +class Royalty: + + numerator: int + denominator: int + payee_address: AccountAddress + + struct_tag: str = "0x4::royalty::Royalty" + + def __init__(self, numerator, denominator, payee_address): + self.numerator = numerator + self.denominator = denominator + self.payee_address = payee_address + + def __str__(self) -> str: + return f"Royalty[numerator: {self.numerator}, denominator: {self.denominator}, payee_address: {self.payee_address}]" + + @staticmethod + def parse(resource: dict[str, Any]) -> Royalty: + return Royalty( + resource["numerator"], + resource["denominator"], + AccountAddress.from_hex(resource["payee_address"]), + ) + + +class Token: + + collection: AccountAddress + collection_id: int + creation_name: Optional[str] + description: str + name: str + uri: str + + struct_tag: str = "0x4::token::Token" + + def __init__( + self, + collection: AccountAddress, + collection_id: int, + creation_name: Optional[str], + description: str, + name: str, + uri: str, + ): + self.collection = collection + self.collection_id = collection_id + self.creation_name = creation_name + self.description = description + self.name = name + self.uri = uri + + def __str__(self) -> str: + return f"Token[collection: {self.collection}, collection_id: {self.collection_id}, creation_name: {self.creation_name}, description: {self.description}, name: {self.name}, uri: {self.uri}]" + + @staticmethod + def parse(resource: dict[str, Any]): + return Token( + AccountAddress.from_hex(resource["collection"]["inner"]), + int(resource["collection_id"]), + resource["creation_name"]["vec"][0] + if len(resource["creation_name"]["vec"]) == 1 + else None, + resource["description"], + resource["name"], + resource["uri"], + ) + + +class InvalidPropertyType(Exception): + """Invalid property type""" + + property_type: Any + + def __init__(self, property_type: Any): + message = f"Unknown property type: {property_type}" + super().__init__(message) + self.property_type = property_type + + +class Property: + + name: str + property_type: str + value: Any + + BOOL: int = 0 + U8: int = 1 + U16: int = 2 + U32: int = 3 + U64: int = 4 + U128: int = 5 + U256: int = 6 + ADDRESS: int = 7 + BYTE_VECTOR: int = 8 + STRING: int = 9 + + def __init__(self, name: str, property_type: str, value: Any): + self.name = name + self.property_type = property_type + self.value = value + + def __str__(self) -> str: + return f"Property[{self.name}, {self.property_type}, {self.value}]" + + def serialize_value(self) -> bytes: + ser = Serializer() + if self.property_type == "bool": + Serializer.bool(ser, self.value) + elif self.property_type == "u8": + Serializer.u8(ser, self.value) + elif self.property_type == "u16": + Serializer.u16(ser, self.value) + elif self.property_type == "u32": + Serializer.u32(ser, self.value) + elif self.property_type == "u64": + Serializer.u64(ser, self.value) + elif self.property_type == "u128": + Serializer.u128(ser, self.value) + elif self.property_type == "u256": + Serializer.u256(ser, self.value) + elif self.property_type == "address": + Serializer.struct(ser, self.value) + elif self.property_type == "0x1::string::String": + Serializer.str(ser, self.value) + elif self.property_type == "vector": + Serializer.to_bytes(ser, self.value) + else: + raise InvalidPropertyType(self.property_type) + return ser.output() + + def to_transaction_arguments(self) -> List[TransactionArgument]: + return [ + TransactionArgument(self.name, Serializer.str), + TransactionArgument(self.property_type, Serializer.str), + TransactionArgument(self.serialize_value(), Serializer.to_bytes), + ] + + @staticmethod + def parse(name: str, property_type: int, value: bytes) -> Property: + deserializer = Deserializer(value) + + if property_type == Property.BOOL: + return Property(name, "bool", deserializer.bool()) + elif property_type == Property.U8: + return Property(name, "u8", deserializer.u8()) + elif property_type == Property.U16: + return Property(name, "u16", deserializer.u16()) + elif property_type == Property.U32: + return Property(name, "u32", deserializer.u32()) + elif property_type == Property.U64: + return Property(name, "u64", deserializer.u64()) + elif property_type == Property.U128: + return Property(name, "u128", deserializer.u128()) + elif property_type == Property.U256: + return Property(name, "u256", deserializer.u256()) + elif property_type == Property.ADDRESS: + return Property(name, "address", AccountAddress.deserialize(deserializer)) + elif property_type == Property.STRING: + return Property(name, "0x1::string::String", deserializer.str()) + elif property_type == Property.BYTE_VECTOR: + return Property(name, "vector", deserializer.to_bytes()) + raise InvalidPropertyType(property_type) + + @staticmethod + def bool(name: str, value: bool) -> Property: + return Property(name, "bool", value) + + @staticmethod + def u8(name: str, value: int) -> Property: + return Property(name, "u8", value) + + @staticmethod + def u16(name: str, value: int) -> Property: + return Property(name, "u16", value) + + @staticmethod + def u32(name: str, value: int) -> Property: + return Property(name, "u32", value) + + @staticmethod + def u64(name: str, value: int) -> Property: + return Property(name, "u64", value) + + @staticmethod + def u128(name: str, value: int) -> Property: + return Property(name, "u128", value) + + @staticmethod + def u256(name: str, value: int) -> Property: + return Property(name, "u256", value) + + @staticmethod + def string(name: str, value: str) -> Property: + return Property(name, "0x1::string::String", value) + + @staticmethod + def bytes(name: str, value: bytes) -> Property: + return Property(name, "vector", value) + + +class PropertyMap: + + properties: List[Property] + + struct_tag: str = "0x4::property_map::PropertyMap" + + def __init__(self, properties: List[Property]): + self.properties = properties + + def __str__(self) -> str: + response = "PropertyMap[" + for prop in self.properties: + response += f"{prop}, " + if len(self.properties) > 0: + response = response[:-2] + response += "]" + return response + + def to_tuple(self) -> Tuple[List[str], List[str], List[bytes]]: + names = [] + types = [] + values = [] + + for prop in self.properties: + names.append(prop.name) + types.append(prop.property_type) + values.append(prop.serialize_value()) + + return (names, types, values) + + @staticmethod + def parse(resource: dict[str, Any]) -> PropertyMap: + props = resource["inner"]["data"] + properties = [] + for prop in props: + properties.append( + Property.parse( + prop["key"], + prop["value"]["type"], + bytes.fromhex(prop["value"]["value"][2:]), + ) + ) + + return PropertyMap(properties) + + +class ReadObject: + resource_map: dict[str, Any] = { + Collection.struct_tag: Collection, + Object.struct_tag: Object, + PropertyMap.struct_tag: PropertyMap, + Royalty.struct_tag: Royalty, + Token.struct_tag: Token, + } + + resources: dict[Any, Any] + + def __init__(self, resources: dict[Any, Any]): + self.resources = resources + + def __str__(self) -> str: + response = "ReadObject" + for (resource_obj, value) in self.resources.items(): + response += f"\n\t{resource_obj.struct_tag}: {value}" + + return response + + +class AptosTokenClient: + """A wrapper around reading and mutating AptosTokens also known as Token Objects""" + + client: RestClient + + def __init__(self, client: RestClient): + self.client = client + + async def read_object(self, address: AccountAddress) -> ReadObject: + resources = {} + + read_resources = await self.client.account_resources(address) + for resource in read_resources: + if resource["type"] in ReadObject.resource_map: + resource_obj = ReadObject.resource_map[resource["type"]] + resources[resource_obj] = resource_obj.parse(resource["data"]) + return ReadObject(resources) + + async def create_collection( + self, + creator: Account, + description: str, + max_supply: int, + name: str, + uri: str, + mutable_description: bool, + mutable_royalty: bool, + mutable_uri: bool, + mutable_token_description: bool, + mutable_token_name: bool, + mutable_token_properties: bool, + mutable_token_uri: bool, + tokens_burnable_by_creator: bool, + tokens_freezable_by_creator: bool, + royalty_numerator: int, + royalty_denominator: int, + ) -> str: + transaction_arguments = [ + TransactionArgument(description, Serializer.str), + TransactionArgument(max_supply, Serializer.u64), + TransactionArgument(name, Serializer.str), + TransactionArgument(uri, Serializer.str), + TransactionArgument(mutable_description, Serializer.bool), + TransactionArgument(mutable_royalty, Serializer.bool), + TransactionArgument(mutable_uri, Serializer.bool), + TransactionArgument(mutable_token_description, Serializer.bool), + TransactionArgument(mutable_token_name, Serializer.bool), + TransactionArgument(mutable_token_properties, Serializer.bool), + TransactionArgument(mutable_token_uri, Serializer.bool), + TransactionArgument(tokens_burnable_by_creator, Serializer.bool), + TransactionArgument(tokens_freezable_by_creator, Serializer.bool), + TransactionArgument(royalty_numerator, Serializer.u64), + TransactionArgument(royalty_denominator, Serializer.u64), + ] + + payload = EntryFunction.natural( + "0x4::aptos_token", + "create_collection", + [], + transaction_arguments, + ) + + signed_transaction = await self.client.create_bcs_signed_transaction( + creator, TransactionPayload(payload) + ) + return await self.client.submit_bcs_transaction(signed_transaction) + + async def mint_token( + self, + creator: Account, + collection: str, + description: str, + name: str, + uri: str, + properties: PropertyMap, + ) -> str: + (property_names, property_types, property_values) = properties.to_tuple() + transaction_arguments = [ + TransactionArgument(collection, Serializer.str), + TransactionArgument(description, Serializer.str), + TransactionArgument(name, Serializer.str), + TransactionArgument(uri, Serializer.str), + TransactionArgument( + property_names, Serializer.sequence_serializer(Serializer.str) + ), + TransactionArgument( + property_types, Serializer.sequence_serializer(Serializer.str) + ), + TransactionArgument( + property_values, Serializer.sequence_serializer(Serializer.to_bytes) + ), + ] + + payload = EntryFunction.natural( + "0x4::aptos_token", + "mint", + [], + transaction_arguments, + ) + + signed_transaction = await self.client.create_bcs_signed_transaction( + creator, TransactionPayload(payload) + ) + return await self.client.submit_bcs_transaction(signed_transaction) + + async def mint_soul_bound_token( + self, + creator: Account, + collection: str, + description: str, + name: str, + uri: str, + properties: PropertyMap, + soul_bound_to: AccountAddress, + ): + (property_names, property_types, property_values) = properties.to_tuple() + transaction_arguments = [ + TransactionArgument(collection, Serializer.str), + TransactionArgument(description, Serializer.str), + TransactionArgument(name, Serializer.str), + TransactionArgument(uri, Serializer.str), + TransactionArgument( + property_names, Serializer.sequence_serializer(Serializer.str) + ), + TransactionArgument( + property_types, Serializer.sequence_serializer(Serializer.str) + ), + TransactionArgument( + property_values, Serializer.sequence_serializer(Serializer.to_bytes) + ), + TransactionArgument(soul_bound_to, Serializer.struct), + ] + + payload = EntryFunction.natural( + "0x4::aptos_token", + "mint_soul_bound", + [], + transaction_arguments, + ) + + signed_transaction = await self.client.create_bcs_signed_transaction( + creator, TransactionPayload(payload) + ) + return await self.client.submit_bcs_transaction(signed_transaction) + + async def burn_token(self, creator: Account, token: AccountAddress) -> str: + payload = EntryFunction.natural( + "0x4::aptos_token", + "burn", + [TypeTag(StructTag.from_str("0x4::token::Token"))], + [TransactionArgument(token, Serializer.struct)], + ) + + signed_transaction = await self.client.create_bcs_signed_transaction( + creator, TransactionPayload(payload) + ) + return await self.client.submit_bcs_transaction(signed_transaction) + + async def freeze_token(self, creator: Account, token: AccountAddress) -> str: + payload = EntryFunction.natural( + "0x4::aptos_token", + "freeze_transfer", + [TypeTag(StructTag.from_str("0x4::token::Token"))], + [TransactionArgument(token, Serializer.struct)], + ) + + signed_transaction = await self.client.create_bcs_signed_transaction( + creator, TransactionPayload(payload) + ) + return await self.client.submit_bcs_transaction(signed_transaction) + + async def unfreeze_token(self, creator: Account, token: AccountAddress) -> str: + payload = EntryFunction.natural( + "0x4::aptos_token", + "unfreeze_transfer", + [TypeTag(StructTag.from_str("0x4::token::Token"))], + [TransactionArgument(token, Serializer.struct)], + ) + + signed_transaction = await self.client.create_bcs_signed_transaction( + creator, TransactionPayload(payload) + ) + return await self.client.submit_bcs_transaction(signed_transaction) + + async def add_token_property( + self, creator: Account, token: AccountAddress, prop: Property + ) -> str: + transaction_arguments = [TransactionArgument(token, Serializer.struct)] + transaction_arguments.extend(prop.to_transaction_arguments()) + + payload = EntryFunction.natural( + "0x4::aptos_token", + "add_property", + [TypeTag(StructTag.from_str("0x4::token::Token"))], + transaction_arguments, + ) + + signed_transaction = await self.client.create_bcs_signed_transaction( + creator, TransactionPayload(payload) + ) + return await self.client.submit_bcs_transaction(signed_transaction) + + async def remove_token_property( + self, creator: Account, token: AccountAddress, name: str + ) -> str: + transaction_arguments = [ + TransactionArgument(token, Serializer.struct), + TransactionArgument(name, Serializer.str), + ] + + payload = EntryFunction.natural( + "0x4::aptos_token", + "remove_property", + [TypeTag(StructTag.from_str("0x4::token::Token"))], + transaction_arguments, + ) + + signed_transaction = await self.client.create_bcs_signed_transaction( + creator, TransactionPayload(payload) + ) + return await self.client.submit_bcs_transaction(signed_transaction) + + async def update_token_property( + self, creator: Account, token: AccountAddress, prop: Property + ) -> str: + transaction_arguments = [TransactionArgument(token, Serializer.struct)] + transaction_arguments.extend(prop.to_transaction_arguments()) + + payload = EntryFunction.natural( + "0x4::aptos_token", + "update_property", + [TypeTag(StructTag.from_str("0x4::token::Token"))], + transaction_arguments, + ) + + signed_transaction = await self.client.create_bcs_signed_transaction( + creator, TransactionPayload(payload) + ) + return await self.client.submit_bcs_transaction(signed_transaction) diff --git a/ecosystem/python/sdk/aptos_sdk/async_client.py b/ecosystem/python/sdk/aptos_sdk/async_client.py index 6850307c18a6b..81d0c770baa3b 100644 --- a/ecosystem/python/sdk/aptos_sdk/async_client.py +++ b/ecosystem/python/sdk/aptos_sdk/async_client.py @@ -116,6 +116,23 @@ async def account_resource( raise ApiError(f"{response.text} - {account_address}", response.status_code) return response.json() + async def account_resources( + self, + account_address: AccountAddress, + ledger_version: int = None, + ) -> List[Dict[str, Any]]: + if not ledger_version: + request = f"{self.base_url}/accounts/{account_address}/resources" + else: + request = f"{self.base_url}/accounts/{account_address}/resources?ledger_version={ledger_version}" + + response = await self.client.get(request) + if response.status_code == 404: + raise AccountNotFound(f"{account_address}", account_address) + if response.status_code >= 400: + raise ApiError(f"{response.text} - {account_address}", response.status_code) + return response.json() + async def get_table_item( self, handle: str, @@ -729,15 +746,30 @@ async def fund_account(self, address: str, amount: int): class ApiError(Exception): """The API returned a non-success status code, e.g., >= 400""" + status_code: int + def __init__(self, message: str, status_code: int): # Call the base class constructor with the parameters it needs super().__init__(message) self.status_code = status_code +class AccountNotFound(Exception): + """The account was not found""" + + account: AccountAddress + + def __init__(self, message: str, account: AccountAddress): + # Call the base class constructor with the parameters it needs + super().__init__(message) + self.account = account + + class ResourceNotFound(Exception): """The underlying resource was not found""" + resource: str + def __init__(self, message: str, resource: str): # Call the base class constructor with the parameters it needs super().__init__(message) diff --git a/ecosystem/python/sdk/examples/async-aptos-token.py b/ecosystem/python/sdk/examples/async-aptos-token.py new file mode 100644 index 0000000000000..78cb3bf532f5a --- /dev/null +++ b/ecosystem/python/sdk/examples/async-aptos-token.py @@ -0,0 +1,116 @@ +# Copyright © Aptos Foundation +# SPDX-License-Identifier: Apache-2.0 + +import asyncio + +from aptos_sdk.account import Account +from aptos_sdk.account_address import AccountAddress +from aptos_sdk.aptos_token_client import (AptosTokenClient, Property, + PropertyMap) +from aptos_sdk.async_client import FaucetClient, RestClient + +from .common import FAUCET_URL, NODE_URL + + +async def main(): + rest_client = RestClient(NODE_URL) + faucet_client = FaucetClient(FAUCET_URL, rest_client) + token_client = AptosTokenClient(rest_client) + alice = Account.generate() + bob = Account.generate() + + collection_name = "Alice's" + token_name = "Alice's first token" + + print("\n=== Addresses ===") + print(f"Alice: {alice.address()}") + print(f"Bob: {bob.address()}") + + bob_fund = faucet_client.fund_account(alice.address(), 100_000_000) + alice_fund = faucet_client.fund_account(bob.address(), 100_000_000) + await asyncio.gather(*[bob_fund, alice_fund]) + + print("\n=== Initial Coin Balances ===") + alice_balance = rest_client.account_balance(alice.address()) + bob_balance = rest_client.account_balance(bob.address()) + [alice_balance, bob_balance] = await asyncio.gather(*[alice_balance, bob_balance]) + print(f"Alice: {alice_balance}") + print(f"Bob: {bob_balance}") + + print("\n=== Creating Collection and Token ===") + + txn_hash = await token_client.create_collection( + alice, + "Alice's simple collection", + 1, + collection_name, + "https://aptos.dev", + True, + True, + True, + True, + True, + True, + True, + True, + True, + 0, + 1, + ) + await rest_client.wait_for_transaction(txn_hash) + + txn_hash = await token_client.mint_token( + alice, + collection_name, + "Alice's simple token", + token_name, + "https://aptos.dev/img/nyan.jpeg", + PropertyMap([Property.string("string", "string value")]), + ) + await rest_client.wait_for_transaction(txn_hash) + + collection_addr = AccountAddress.for_named_collection( + alice.address(), collection_name + ) + token_addr = AccountAddress.for_named_token( + alice.address(), collection_name, token_name + ) + """ + alice_address = AccountAddress.from_hex("0xa018017dc40fd081d2001acdb2660058ed2011f2790a42c2a40bab99909fbde5") + collection_addr = AccountAddress.for_named_collection(alice_address, collection_name) + token_addr = AccountAddress.for_named_token(alice_address, collection_name, token_name) + """ + + collection_data = await token_client.read_object(collection_addr) + print(f"Alice's collection: {collection_data}") + token_data = await token_client.read_object(token_addr) + print(f"Alice's token: {token_data}") + + txn_hash = await token_client.add_token_property( + alice, token_addr, Property.bool("test", False) + ) + await rest_client.wait_for_transaction(txn_hash) + token_data = await token_client.read_object(token_addr) + print(f"Alice's token: {token_data}") + txn_hash = await token_client.remove_token_property(alice, token_addr, "string") + await rest_client.wait_for_transaction(txn_hash) + token_data = await token_client.read_object(token_addr) + print(f"Alice's token: {token_data}") + txn_hash = await token_client.update_token_property( + alice, token_addr, Property.bool("test", True) + ) + await rest_client.wait_for_transaction(txn_hash) + token_data = await token_client.read_object(token_addr) + print(f"Alice's token: {token_data}") + txn_hash = await token_client.add_token_property( + alice, token_addr, Property.bytes("bytes", b"\x00\x01") + ) + await rest_client.wait_for_transaction(txn_hash) + token_data = await token_client.read_object(token_addr) + print(f"Alice's token: {token_data}") + + await rest_client.close() + + +if __name__ == "__main__": + asyncio.run(main()) From 8b74f89f142a6e7d587301b050edb5aa216e6bf6 Mon Sep 17 00:00:00 2001 From: David Wolinsky Date: Sat, 25 Mar 2023 21:32:41 -0700 Subject: [PATCH 13/13] docs fix --- developer-docs-site/docs/guides/aptos-name-service-connector.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/developer-docs-site/docs/guides/aptos-name-service-connector.md b/developer-docs-site/docs/guides/aptos-name-service-connector.md index cfe8d679207d7..5489a28956594 100644 --- a/developer-docs-site/docs/guides/aptos-name-service-connector.md +++ b/developer-docs-site/docs/guides/aptos-name-service-connector.md @@ -70,7 +70,7 @@ The `AptosNamesConnector` component supports both mainnet and testnet. To connec ## Example The following example shows how to use the `AptosNamesConnector` component in a React application: - + - Add a ‘claim name’ button to any page in your application. This allows your users to directly create an Aptos name, giving them a human-readable .apt name for their Aptos wallet address. You can customize the look of the button to suit your application. Here is an example on the profile page of an NFT marketplace.