aptos_token - [mainnet]
This defines a minimally viable token for no-code solutions akin to 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
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;
Constants
The collection does not exist
const ECOLLECTION_DOES_NOT_EXIST: u64 = 1;
The field being changed is not mutable
const EFIELD_NOT_MUTABLE: u64 = 4;
The provided signer is not the creator
const ENOT_CREATOR: u64 = 3;
The token does not exist
const ETOKEN_DOES_NOT_EXIST: u64 = 2;
The property map being mutated is not mutable
const EPROPERTIES_NOT_MUTABLE: u64 = 6;
The token being burned is not burnable
const ETOKEN_NOT_BURNABLE: u64 = 5;
Resources
AptosCollection
Storage state for managing the no-code Collection.
#[resource_group_member(#[group = 0x1::object::ObjectGroup])]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
AptosToken
Storage state for managing the no-code Token.
#[resource_group_member(#[group = 0x1::object::ObjectGroup])]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: property_map::MutatorRef
- Used to mutate properties
Functions
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,) { create_collection_object( creator, 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 );}
create_collection_object
public fun create_collection_object(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): object::Object<aptos_token::AptosCollection>
Implementation
public fun create_collection_object( 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,): Object<AptosCollection> { 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); object::object_from_constructor_ref(&constructor_ref)}
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 { mint_token_object(creator, collection, description, name, uri, property_keys, property_types, property_values);}
mint_token_object
Mint a token into an existing collection, and retrieve the object / address of the token.
public fun mint_token_object(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::Object<aptos_token::AptosToken>
Implementation
public fun mint_token_object( creator: &signer, collection: String, description: String, name: String, uri: String, property_keys: vector<String>, property_types: vector<String>, property_values: vector<vector<u8>>,): Object<AptosToken> 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);
// If tokens are freezable, add a transfer ref to be able to freeze transfers let freezable_by_creator = are_collection_tokens_freezable(collection); if (freezable_by_creator) { let aptos_token_addr = object::address_from_constructor_ref(&constructor_ref); let aptos_token = &mut AptosToken[aptos_token_addr]; let transfer_ref = object::generate_transfer_ref(&constructor_ref); aptos_token.transfer_ref.fill(transfer_ref); };
object::object_from_constructor_ref(&constructor_ref)}
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 { mint_soul_bound_token_object( creator, collection, description, name, uri, property_keys, property_types, property_values, soul_bound_to );}
mint_soul_bound_token_object
With an existing collection, directly mint a soul bound token into the recipient’s account.
public fun mint_soul_bound_token_object(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): object::Object<aptos_token::AptosToken>
Implementation
public fun mint_soul_bound_token_object( 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,): Object<AptosToken> 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);
object::object_from_constructor_ref(&constructor_ref)}
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 aptos_token = AptosToken { burn_ref, transfer_ref: option::none(), mutator_ref, property_mutator_ref: property_map::generate_mutator_ref(&constructor_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}
borrow
fun borrow<T: key>(token: &object::Object<T>): &aptos_token::AptosToken
Implementation
inline fun borrow<T: key>(token: &Object<T>): &AptosToken { let token_address = object::object_address(token); assert!( exists<AptosToken>(token_address), error::not_found(ETOKEN_DOES_NOT_EXIST), ); &AptosToken[token_address]}
are_properties_mutable
#[view]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 AptosCollection { let collection = token::collection_object(token); borrow_collection(&collection).mutable_token_properties}
is_burnable
#[view]public fun is_burnable<T: key>(token: object::Object<T>): bool
Implementation
public fun is_burnable<T: key>(token: Object<T>): bool acquires AptosToken { borrow(&token).burn_ref.is_some()}
is_freezable_by_creator
#[view]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))}
is_mutable_description
#[view]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))}
is_mutable_name
#[view]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))}
is_mutable_uri
#[view]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))}
authorized_borrow
fun authorized_borrow<T: key>(token: &object::Object<T>, creator: &signer): &aptos_token::AptosToken
Implementation
inline fun authorized_borrow<T: key>(token: &Object<T>, creator: &signer): &AptosToken { let token_address = object::object_address(token); assert!( exists<AptosToken>(token_address), error::not_found(ETOKEN_DOES_NOT_EXIST), );
assert!( token::creator(*token) == signer::address_of(creator), error::permission_denied(ENOT_CREATOR), ); &AptosToken[token_address]}
burn
public entry fun burn<T: key>(creator: &signer, token: object::Object<T>)
Implementation
public entry fun burn<T: key>(creator: &signer, token: Object<T>) acquires AptosToken { let aptos_token = authorized_borrow(&token, creator); assert!( aptos_token.burn_ref.is_some(), 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; property_map::burn(property_mutator_ref); token::burn(burn_ref.extract());}
freeze_transfer
public entry fun freeze_transfer<T: key>(creator: &signer, token: object::Object<T>)
Implementation
public entry fun freeze_transfer<T: key>(creator: &signer, token: Object<T>) acquires AptosCollection, AptosToken { let aptos_token = authorized_borrow(&token, creator); assert!( are_collection_tokens_freezable(token::collection_object(token)) && aptos_token.transfer_ref.is_some(), error::permission_denied(EFIELD_NOT_MUTABLE), ); object::disable_ungated_transfer(aptos_token.transfer_ref.borrow());}
unfreeze_transfer
public entry fun unfreeze_transfer<T: key>(creator: &signer, token: object::Object<T>)
Implementation
public entry fun unfreeze_transfer<T: key>( creator: &signer, token: Object<T>) acquires AptosCollection, AptosToken { let aptos_token = authorized_borrow(&token, creator); assert!( are_collection_tokens_freezable(token::collection_object(token)) && aptos_token.transfer_ref.is_some(), error::permission_denied(EFIELD_NOT_MUTABLE), ); object::enable_ungated_transfer(aptos_token.transfer_ref.borrow());}
set_description
public entry fun set_description<T: key>(creator: &signer, token: object::Object<T>, description: string::String)
Implementation
public entry 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, creator); token::set_description(aptos_token.mutator_ref.borrow(), description);}
set_name
public entry fun set_name<T: key>(creator: &signer, token: object::Object<T>, name: string::String)
Implementation
public entry 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, creator); token::set_name(aptos_token.mutator_ref.borrow(), name);}
set_uri
public entry fun set_uri<T: key>(creator: &signer, token: object::Object<T>, uri: string::String)
Implementation
public entry 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, creator); token::set_uri(aptos_token.mutator_ref.borrow(), uri);}
add_property
public entry fun add_property<T: key>(creator: &signer, token: object::Object<T>, key: string::String, type: string::String, value: vector<u8>)
Implementation
public entry fun add_property<T: key>( creator: &signer, token: Object<T>, key: String, type: String, value: vector<u8>,) acquires AptosCollection, AptosToken { let aptos_token = authorized_borrow(&token, creator); assert!( are_properties_mutable(token), error::permission_denied(EPROPERTIES_NOT_MUTABLE), );
property_map::add(&aptos_token.property_mutator_ref, key, type, value);}
add_typed_property
public entry fun add_typed_property<T: key, V: drop>(creator: &signer, token: object::Object<T>, key: string::String, value: V)
Implementation
public entry fun add_typed_property<T: key, V: drop>( creator: &signer, token: Object<T>, key: String, value: V,) acquires AptosCollection, AptosToken { let aptos_token = authorized_borrow(&token, creator); assert!( are_properties_mutable(token), error::permission_denied(EPROPERTIES_NOT_MUTABLE), );
property_map::add_typed(&aptos_token.property_mutator_ref, key, value);}
remove_property
public entry fun remove_property<T: key>(creator: &signer, token: object::Object<T>, key: string::String)
Implementation
public entry fun remove_property<T: key>( creator: &signer, token: Object<T>, key: String,) acquires AptosCollection, AptosToken { let aptos_token = authorized_borrow(&token, creator); assert!( are_properties_mutable(token), error::permission_denied(EPROPERTIES_NOT_MUTABLE), );
property_map::remove(&aptos_token.property_mutator_ref, &key);}
update_property
public entry fun update_property<T: key>(creator: &signer, token: object::Object<T>, key: string::String, type: string::String, value: vector<u8>)
Implementation
public entry fun update_property<T: key>( creator: &signer, token: Object<T>, key: String, type: String, value: vector<u8>,) acquires AptosCollection, AptosToken { let aptos_token = authorized_borrow(&token, creator); assert!( are_properties_mutable(token), error::permission_denied(EPROPERTIES_NOT_MUTABLE), );
property_map::update(&aptos_token.property_mutator_ref, &key, type, value);}
update_typed_property
public entry fun update_typed_property<T: key, V: drop>(creator: &signer, token: object::Object<T>, key: string::String, value: V)
Implementation
public entry fun update_typed_property<T: key, V: drop>( creator: &signer, token: Object<T>, key: String, value: V,) acquires AptosCollection, AptosToken { let aptos_token = authorized_borrow(&token, creator); assert!( are_properties_mutable(token), error::permission_denied(EPROPERTIES_NOT_MUTABLE), );
property_map::update_typed(&aptos_token.property_mutator_ref, &key, value);}
collection_object
fun collection_object(creator: &signer, name: &string::String): object::Object<aptos_token::AptosCollection>
Implementation
inline fun collection_object(creator: &signer, name: &String): Object<AptosCollection> { let collection_addr = collection::create_collection_address(&signer::address_of(creator), name); object::address_to_object<AptosCollection>(collection_addr)}
borrow_collection
fun borrow_collection<T: key>(token: &object::Object<T>): &aptos_token::AptosCollection
Implementation
inline fun borrow_collection<T: key>(token: &Object<T>): &AptosCollection { let collection_address = object::object_address(token); assert!( exists<AptosCollection>(collection_address), error::not_found(ECOLLECTION_DOES_NOT_EXIST), ); &AptosCollection[collection_address]}
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}
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 { borrow_collection(&collection).royalty_mutator_ref.is_some()}
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}
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}
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}
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}
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}
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}
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}
authorized_borrow_collection
fun authorized_borrow_collection<T: key>(collection: &object::Object<T>, creator: &signer): &aptos_token::AptosCollection
Implementation
inline fun authorized_borrow_collection<T: key>(collection: &Object<T>, creator: &signer): &AptosCollection { let collection_address = object::object_address(collection); assert!( exists<AptosCollection>(collection_address), error::not_found(ECOLLECTION_DOES_NOT_EXIST), ); assert!( collection::creator(*collection) == signer::address_of(creator), error::permission_denied(ENOT_CREATOR), ); &AptosCollection[collection_address]}
set_collection_description
public entry fun set_collection_description<T: key>(creator: &signer, collection: object::Object<T>, description: string::String)
Implementation
public entry fun set_collection_description<T: key>( creator: &signer, collection: Object<T>, description: String,) acquires AptosCollection { let aptos_collection = authorized_borrow_collection(&collection, creator); assert!( aptos_collection.mutable_description, error::permission_denied(EFIELD_NOT_MUTABLE), ); collection::set_description(aptos_collection.mutator_ref.borrow(), description);}
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, creator); assert!( aptos_collection.royalty_mutator_ref.is_some(), error::permission_denied(EFIELD_NOT_MUTABLE), ); royalty::update(aptos_collection.royalty_mutator_ref.borrow(), royalty);}
set_collection_royalties_call
entry fun set_collection_royalties_call<T: key>(creator: &signer, collection: object::Object<T>, royalty_numerator: u64, royalty_denominator: u64, payee_address: address)
Implementation
entry fun set_collection_royalties_call<T: key>( creator: &signer, 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, royalty);}
set_collection_uri
public entry fun set_collection_uri<T: key>(creator: &signer, collection: object::Object<T>, uri: string::String)
Implementation
public entry fun set_collection_uri<T: key>( creator: &signer, collection: Object<T>, uri: String,) acquires AptosCollection { let aptos_collection = authorized_borrow_collection(&collection, creator); assert!( aptos_collection.mutable_uri, error::permission_denied(EFIELD_NOT_MUTABLE), ); collection::set_uri(aptos_collection.mutator_ref.borrow(), uri);}