token - [testnet]
Esta página aún no está disponible en tu idioma.
This module provides the foundation for Tokens. Checkout our developer doc on our token standard https://aptos.dev/standards
use 0x1::account;use 0x1::error;use 0x1::event;use 0x1::features;use 0x1::option;use 0x1::signer;use 0x1::string;use 0x1::table;use 0x1::timestamp;use 0x3::property_map;use 0x3::token_event_store;
Constants
Insufficient token balance
const EINSUFFICIENT_BALANCE: u64 = 5;
The URI is too long
const EURI_TOO_LONG: u64 = 27;
const MAX_URI_LENGTH: u64 = 512;
const BURNABLE_BY_CREATOR: vector<u8> = [84, 79, 75, 69, 78, 95, 66, 85, 82, 78, 65, 66, 76, 69, 95, 66, 89, 95, 67, 82, 69, 65, 84, 79, 82];
const BURNABLE_BY_OWNER: vector<u8> = [84, 79, 75, 69, 78, 95, 66, 85, 82, 78, 65, 66, 76, 69, 95, 66, 89, 95, 79, 87, 78, 69, 82];
const COLLECTION_DESCRIPTION_MUTABLE_IND: u64 = 0;
const COLLECTION_MAX_MUTABLE_IND: u64 = 2;
const COLLECTION_URI_MUTABLE_IND: u64 = 1;
The token has balance and cannot be initialized
const EALREADY_HAS_BALANCE: u64 = 0;
Reserved fields for token contract Cannot be updated by user
const ECANNOT_UPDATE_RESERVED_PROPERTY: u64 = 32;
There isn’t any collection under this account
const ECOLLECTIONS_NOT_PUBLISHED: u64 = 1;
The collection already exists
const ECOLLECTION_ALREADY_EXISTS: u64 = 3;
The collection name is too long
const ECOLLECTION_NAME_TOO_LONG: u64 = 25;
Cannot find collection in creator’s account
const ECOLLECTION_NOT_PUBLISHED: u64 = 2;
Exceeds the collection’s maximal number of token_data
const ECREATE_WOULD_EXCEED_COLLECTION_MAXIMUM: u64 = 4;
Token is not burnable by creator
const ECREATOR_CANNOT_BURN_TOKEN: u64 = 31;
The field is not mutable
const EFIELD_NOT_MUTABLE: u64 = 13;
Withdraw capability doesn’t have sufficient amount
const EINSUFFICIENT_WITHDRAW_CAPABILITY_AMOUNT: u64 = 38;
Collection or tokendata maximum must be larger than supply
const EINVALID_MAXIMUM: u64 = 36;
Royalty invalid if the numerator is larger than the denominator
const EINVALID_ROYALTY_NUMERATOR_DENOMINATOR: u64 = 34;
Cannot merge the two tokens with different token id
const EINVALID_TOKEN_MERGE: u64 = 6;
Exceed the token data maximal allowed
const EMINT_WOULD_EXCEED_TOKEN_MAXIMUM: u64 = 7;
The NFT name is too long
const ENFT_NAME_TOO_LONG: u64 = 26;
Cannot split a token that only has 1 amount
const ENFT_NOT_SPLITABLE: u64 = 18;
No burn capability
const ENO_BURN_CAPABILITY: u64 = 8;
Cannot burn 0 Token
const ENO_BURN_TOKEN_WITH_ZERO_AMOUNT: u64 = 29;
Cannot deposit a Token with 0 amount
const ENO_DEPOSIT_TOKEN_WITH_ZERO_AMOUNT: u64 = 28;
No mint capability
const ENO_MINT_CAPABILITY: u64 = 19;
Not authorized to mutate
const ENO_MUTATE_CAPABILITY: u64 = 14;
Token not in the token store
const ENO_TOKEN_IN_TOKEN_STORE: u64 = 15;
Token is not burnable by owner
const EOWNER_CANNOT_BURN_TOKEN: u64 = 30;
The property is reserved by token standard
const EPROPERTY_RESERVED_BY_STANDARD: u64 = 40;
Royalty payee account does not exist
const EROYALTY_PAYEE_ACCOUNT_DOES_NOT_EXIST: u64 = 35;
TOKEN with 0 amount is not allowed
const ETOKEN_CANNOT_HAVE_ZERO_AMOUNT: u64 = 33;
TokenData already exists
const ETOKEN_DATA_ALREADY_EXISTS: u64 = 9;
TokenData not published
const ETOKEN_DATA_NOT_PUBLISHED: u64 = 10;
Token Properties count doesn’t match
const ETOKEN_PROPERTIES_COUNT_NOT_MATCH: u64 = 37;
Cannot split token to an amount larger than its amount
const ETOKEN_SPLIT_AMOUNT_LARGER_OR_EQUAL_TO_TOKEN_AMOUNT: u64 = 12;
TokenStore doesn’t exist
const ETOKEN_STORE_NOT_PUBLISHED: u64 = 11;
User didn’t opt-in direct transfer
const EUSER_NOT_OPT_IN_DIRECT_TRANSFER: u64 = 16;
Withdraw proof expires
const EWITHDRAW_PROOF_EXPIRES: u64 = 39;
Cannot withdraw 0 token
const EWITHDRAW_ZERO: u64 = 17;
const MAX_COLLECTION_NAME_LENGTH: u64 = 128;
const MAX_NFT_NAME_LENGTH: u64 = 128;
const TOKEN_DESCRIPTION_MUTABLE_IND: u64 = 3;
const TOKEN_MAX_MUTABLE_IND: u64 = 0;
const TOKEN_PROPERTY_MUTABLE: vector<u8> = [84, 79, 75, 69, 78, 95, 80, 82, 79, 80, 69, 82, 84, 89, 95, 77, 85, 84, 65, 84, 66, 76, 69];
const TOKEN_PROPERTY_MUTABLE_IND: u64 = 4;
const TOKEN_PROPERTY_VALUE_MUTABLE_IND: u64 = 5;
const TOKEN_ROYALTY_MUTABLE_IND: u64 = 2;
const TOKEN_URI_MUTABLE_IND: u64 = 1;
Structs
Token
struct Token has store
Fields
-
id: token::TokenId
-
amount: u64
- the amount of tokens. Only property_version = 0 can have a value bigger than 1.
-
token_properties: property_map::PropertyMap
- The properties with this token. when property_version = 0, the token_properties are the same as default_properties in TokenData, we don't store it. when the property_map mutates, a new property_version is assigned to the token.
TokenId
global unique identifier of a token
struct TokenId has copy, drop, store
Fields
-
token_data_id: token::TokenDataId
- the id to the common token data shared by token with different property_version
-
property_version: u64
- The version of the property map; when a fungible token is mutated, a new property version is created and assigned to the token to make it an NFT
TokenDataId
globally unique identifier of tokendata
struct TokenDataId has copy, drop, store
Fields
-
creator: address
- The address of the creator, eg: 0xcafe
-
collection: string::String
- The name of collection; this is unique under the same account, eg: "Aptos Animal Collection"
-
name: string::String
- The name of the token; this is the same as the name field of TokenData
TokenData
The shared TokenData by tokens with different property_version
struct TokenData has store
Fields
-
maximum: u64
- The maximal number of tokens that can be minted under this TokenData; if the maximum is 0, there is no limit
-
largest_property_version: u64
- The current largest property version of all tokens with this TokenData
-
supply: u64
- The number of tokens with this TokenData. Supply is only tracked for the limited token whose maximum is not 0
-
uri: string::String
- The Uniform Resource Identifier (uri) pointing to the JSON file stored in off-chain storage; the URL length should be less than 512 characters, eg: https://arweave.net/Fmmn4ul-7Mv6vzm7JwE69O-I-vd6Bz2QriJO1niwCh4
-
royalty: token::Royalty
- The denominator and numerator for calculating the royalty fee; it also contains payee account address for depositing the Royalty
-
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"
-
description: string::String
- Describes this Token
-
default_properties: property_map::PropertyMap
- The properties are stored in the TokenData that are shared by all tokens
-
mutability_config: token::TokenMutabilityConfig
- Control the TokenData field mutability
Royalty
The royalty of a token
struct Royalty has copy, drop, store
Fields
-
royalty_points_numerator: u64
-
royalty_points_denominator: u64
-
payee_address: address
- if the token is jointly owned by multiple creators, the group of creators should create a shared account. the payee_address will be the shared account address.
TokenMutabilityConfig
This config specifies which fields in the TokenData are mutable
struct TokenMutabilityConfig has copy, drop, store
Fields
-
maximum: bool
- control if the token maximum is mutable
-
uri: bool
- control if the token uri is mutable
-
royalty: bool
- control if the token royalty is mutable
-
description: bool
- control if the token description is mutable
-
properties: bool
- control if the property map is mutable
CollectionMutabilityConfig
This config specifies which fields in the Collection are mutable
struct CollectionMutabilityConfig has copy, drop, store
Fields
-
description: bool
- control if description is mutable
-
uri: bool
- control if uri is mutable
-
maximum: bool
- control if collection maxium is mutable
CollectionData
Represent the collection metadata
struct CollectionData has store
Fields
-
description: string::String
- A description for the token collection Eg: "Aptos Toad Overload"
-
name: string::String
- The collection name, which should be unique among all collections by the creator; the name should also be smaller than 128 characters, eg: "Animal Collection"
-
uri: string::String
- The URI for the collection; its length should be smaller than 512 characters
-
supply: u64
- The number of different TokenData entries in this collection
-
maximum: u64
- If maximal is a non-zero value, the number of created TokenData entries should be smaller or equal to this maximum If maximal is 0, Aptos doesn't track the supply of this collection, and there is no limit
-
mutability_config: token::CollectionMutabilityConfig
- control which collectionData field is mutable
WithdrawCapability
capability to withdraw without signer, this struct should be non-copyable
struct WithdrawCapability has drop, store
Fields
-
token_owner: address
-
token_id: token::TokenId
-
amount: u64
-
expiration_sec: u64
DepositEvent
Set of data sent to the event stream during a receive
struct DepositEvent has drop, store
Fields
-
id: token::TokenId
-
amount: u64
TokenDeposit
Set of data sent to the event stream during a receive
#[event]struct TokenDeposit has drop, store
Fields
-
account: address
-
id: token::TokenId
-
amount: u64
Deposit
Set of data sent to the event stream during a receive
#[event]#[deprecated]struct Deposit has drop, store
Fields
-
id: token::TokenId
-
amount: u64
WithdrawEvent
Set of data sent to the event stream during a withdrawal
struct WithdrawEvent has drop, store
Fields
-
id: token::TokenId
-
amount: u64
Withdraw
Set of data sent to the event stream during a withdrawal
#[event]#[deprecated]struct Withdraw has drop, store
Fields
-
id: token::TokenId
-
amount: u64
TokenWithdraw
Set of data sent to the event stream during a withdrawal
#[event]struct TokenWithdraw has drop, store
Fields
-
account: address
-
id: token::TokenId
-
amount: u64
CreateTokenDataEvent
token creation event id of token created
struct CreateTokenDataEvent has drop, store
Fields
-
id: token::TokenDataId
-
description: string::String
-
maximum: u64
-
uri: string::String
-
royalty_payee_address: address
-
royalty_points_denominator: u64
-
royalty_points_numerator: u64
-
name: string::String
-
mutability_config: token::TokenMutabilityConfig
-
property_keys: vector<string::String>
-
property_values: vector<vector<u8>>
-
property_types: vector<string::String>
CreateTokenData
#[event]#[deprecated]struct CreateTokenData has drop, store
Fields
-
id: token::TokenDataId
-
description: string::String
-
maximum: u64
-
uri: string::String
-
royalty_payee_address: address
-
royalty_points_denominator: u64
-
royalty_points_numerator: u64
-
name: string::String
-
mutability_config: token::TokenMutabilityConfig
-
property_keys: vector<string::String>
-
property_values: vector<vector<u8>>
-
property_types: vector<string::String>
TokenDataCreation
#[event]struct TokenDataCreation has drop, store
Fields
-
creator: address
-
id: token::TokenDataId
-
description: string::String
-
maximum: u64
-
uri: string::String
-
royalty_payee_address: address
-
royalty_points_denominator: u64
-
royalty_points_numerator: u64
-
name: string::String
-
mutability_config: token::TokenMutabilityConfig
-
property_keys: vector<string::String>
-
property_values: vector<vector<u8>>
-
property_types: vector<string::String>
MintTokenEvent
mint token event. This event triggered when creator adds more supply to existing token
struct MintTokenEvent has drop, store
Fields
-
id: token::TokenDataId
-
amount: u64
MintToken
#[event]#[deprecated]struct MintToken has drop, store
Fields
-
id: token::TokenDataId
-
amount: u64
Mint
#[event]struct Mint has drop, store
Fields
-
creator: address
-
id: token::TokenDataId
-
amount: u64
BurnTokenEvent
struct BurnTokenEvent has drop, store
Fields
-
id: token::TokenId
-
amount: u64
BurnToken
#[event]#[deprecated]struct BurnToken has drop, store
Fields
-
id: token::TokenId
-
amount: u64
Burn
#[event]struct Burn has drop, store
Fields
-
account: address
-
id: token::TokenId
-
amount: u64
MutateTokenPropertyMapEvent
struct MutateTokenPropertyMapEvent has drop, store
Fields
-
old_id: token::TokenId
-
new_id: token::TokenId
-
keys: vector<string::String>
-
values: vector<vector<u8>>
-
types: vector<string::String>
MutateTokenPropertyMap
#[event]#[deprecated]struct MutateTokenPropertyMap has drop, store
Fields
-
old_id: token::TokenId
-
new_id: token::TokenId
-
keys: vector<string::String>
-
values: vector<vector<u8>>
-
types: vector<string::String>
MutatePropertyMap
#[event]struct MutatePropertyMap has drop, store
Fields
-
account: address
-
old_id: token::TokenId
-
new_id: token::TokenId
-
keys: vector<string::String>
-
values: vector<vector<u8>>
-
types: vector<string::String>
CreateCollectionEvent
create collection event with creator address and collection name
struct CreateCollectionEvent has drop, store
Fields
-
creator: address
-
collection_name: string::String
-
uri: string::String
-
description: string::String
-
maximum: u64
CreateCollection
#[event]struct CreateCollection has drop, store
Fields
-
creator: address
-
collection_name: string::String
-
uri: string::String
-
description: string::String
-
maximum: u64
Resources
TokenStore
Represents token resources owned by token owner
struct TokenStore has key
Fields
-
tokens: table::Table<token::TokenId, token::Token>
- the tokens owned by a token owner
-
direct_transfer: bool
-
deposit_events: event::EventHandle<token::DepositEvent>
-
withdraw_events: event::EventHandle<token::WithdrawEvent>
-
burn_events: event::EventHandle<token::BurnTokenEvent>
-
mutate_token_property_events: event::EventHandle<token::MutateTokenPropertyMapEvent>
Collections
Represent collection and token metadata for a creator
struct Collections has key
Fields
-
collection_data: table::Table<string::String, token::CollectionData>
-
token_data: table::Table<token::TokenDataId, token::TokenData>
-
create_collection_events: event::EventHandle<token::CreateCollectionEvent>
-
create_token_data_events: event::EventHandle<token::CreateTokenDataEvent>
-
mint_token_events: event::EventHandle<token::MintTokenEvent>
Functions
create_collection_script
create a empty token collection with parameters
public entry fun create_collection_script(creator: &signer, name: string::String, description: string::String, uri: string::String, maximum: u64, mutate_setting: vector<bool>)
Implementation
public entry fun create_collection_script( creator: &signer, name: String, description: String, uri: String, maximum: u64, mutate_setting: vector<bool>,) acquires Collections { create_collection( creator, name, description, uri, maximum, mutate_setting );}
create_token_script
create token with raw inputs
public entry fun create_token_script(account: &signer, collection: string::String, name: string::String, description: string::String, balance: u64, maximum: u64, uri: string::String, royalty_payee_address: address, royalty_points_denominator: u64, royalty_points_numerator: u64, mutate_setting: vector<bool>, property_keys: vector<string::String>, property_values: vector<vector<u8>>, property_types: vector<string::String>)
Implementation
public entry fun create_token_script( account: &signer, collection: String, name: String, description: String, balance: u64, maximum: u64, uri: String, royalty_payee_address: address, royalty_points_denominator: u64, royalty_points_numerator: u64, mutate_setting: vector<bool>, property_keys: vector<String>, property_values: vector<vector<u8>>, property_types: vector<String>) acquires Collections, TokenStore { let token_mut_config = create_token_mutability_config(&mutate_setting); let tokendata_id = create_tokendata( account, collection, name, description, maximum, uri, royalty_payee_address, royalty_points_denominator, royalty_points_numerator, token_mut_config, property_keys, property_values, property_types );
mint_token( account, tokendata_id, balance, );}
mint_script
Mint more token from an existing token_data. Mint only adds more token to property_version 0
public entry fun mint_script(account: &signer, token_data_address: address, collection: string::String, name: string::String, amount: u64)
Implementation
public entry fun mint_script( account: &signer, token_data_address: address, collection: String, name: String, amount: u64,) acquires Collections, TokenStore { let token_data_id = create_token_data_id( token_data_address, collection, name, ); // only creator of the tokendata can mint more tokens for now assert!(token_data_id.creator == signer::address_of(account), error::permission_denied(ENO_MINT_CAPABILITY)); mint_token( account, token_data_id, amount, );}
mutate_token_properties
mutate the token property and save the new property in TokenStore if the token property_version is 0, we will create a new property_version per token to generate a new token_id per token if the token property_version is not 0, we will just update the propertyMap and use the existing token_id (property_version)
public entry fun mutate_token_properties(account: &signer, token_owner: address, creator: address, collection_name: string::String, token_name: string::String, token_property_version: u64, amount: u64, keys: vector<string::String>, values: vector<vector<u8>>, types: vector<string::String>)
Implementation
public entry fun mutate_token_properties( account: &signer, token_owner: address, creator: address, collection_name: String, token_name: String, token_property_version: u64, amount: u64, keys: vector<String>, values: vector<vector<u8>>, types: vector<String>,) acquires Collections, TokenStore { assert!(signer::address_of(account) == creator, error::not_found(ENO_MUTATE_CAPABILITY)); let token_id = create_token_id_raw( creator, collection_name, token_name, token_property_version, ); // give a new property_version for each token for (i in 0..amount) { mutate_one_token(account, token_owner, token_id, keys, values, types); };}
direct_transfer_script
public entry fun direct_transfer_script(sender: &signer, receiver: &signer, creators_address: address, collection: string::String, name: string::String, property_version: u64, amount: u64)
Implementation
public entry fun direct_transfer_script( sender: &signer, receiver: &signer, creators_address: address, collection: String, name: String, property_version: u64, amount: u64,) acquires TokenStore { let token_id = create_token_id_raw(creators_address, collection, name, property_version); direct_transfer(sender, receiver, token_id, amount);}
opt_in_direct_transfer
public entry fun opt_in_direct_transfer(account: &signer, opt_in: bool)
Implementation
public entry fun opt_in_direct_transfer(account: &signer, opt_in: bool) acquires TokenStore { let addr = signer::address_of(account); initialize_token_store(account); let opt_in_flag = &mut TokenStore[addr].direct_transfer; *opt_in_flag = opt_in; token_event_store::emit_token_opt_in_event(account, opt_in);}
transfer_with_opt_in
Transfers amount
of tokens from from
to to
.
The receiver to
has to opt-in direct transfer first
public entry fun transfer_with_opt_in(from: &signer, creator: address, collection_name: string::String, token_name: string::String, token_property_version: u64, to: address, amount: u64)
Implementation
public entry fun transfer_with_opt_in( from: &signer, creator: address, collection_name: String, token_name: String, token_property_version: u64, to: address, amount: u64,) acquires TokenStore { let token_id = create_token_id_raw(creator, collection_name, token_name, token_property_version); transfer(from, token_id, to, amount);}
burn_by_creator
Burn a token by creator when the token’s BURNABLE_BY_CREATOR is true The token is owned at address owner
public entry fun burn_by_creator(creator: &signer, owner: address, collection: string::String, name: string::String, property_version: u64, amount: u64)
Implementation
public entry fun burn_by_creator( creator: &signer, owner: address, collection: String, name: String, property_version: u64, amount: u64,) acquires Collections, TokenStore { let creator_address = signer::address_of(creator); assert!(amount > 0, error::invalid_argument(ENO_BURN_TOKEN_WITH_ZERO_AMOUNT)); let token_id = create_token_id_raw(creator_address, collection, name, property_version); let creator_addr = token_id.token_data_id.creator; assert!( exists<Collections>(creator_addr), error::not_found(ECOLLECTIONS_NOT_PUBLISHED), );
let collections = &mut Collections[creator_address]; assert!( collections.token_data.contains(token_id.token_data_id), error::not_found(ETOKEN_DATA_NOT_PUBLISHED), );
let token_data = collections.token_data.borrow_mut(token_id.token_data_id);
// The property should be explicitly set in the property_map for creator to burn the token assert!( token_data.default_properties.contains_key(&string::utf8(BURNABLE_BY_CREATOR)), error::permission_denied(ECREATOR_CANNOT_BURN_TOKEN) );
let burn_by_creator_flag = token_data.default_properties.read_bool(&string::utf8(BURNABLE_BY_CREATOR)); assert!(burn_by_creator_flag, error::permission_denied(ECREATOR_CANNOT_BURN_TOKEN));
// Burn the tokens. let Token { id: _, amount: burned_amount, token_properties: _ } = withdraw_with_event_internal(owner, token_id, amount); let token_store = &mut TokenStore[owner]; if (std::features::module_event_migration_enabled()) { event::emit(Burn { account: owner, id: token_id, amount: burned_amount }); } else { event::emit_event<BurnTokenEvent>( &mut token_store.burn_events, BurnTokenEvent { id: token_id, amount: burned_amount } ); };
if (token_data.maximum > 0) { token_data.supply -= burned_amount;
// Delete the token_data if supply drops to 0. if (token_data.supply == 0) { destroy_token_data(collections.token_data.remove(token_id.token_data_id));
// update the collection supply let collection_data = collections.collection_data.borrow_mut(token_id.token_data_id.collection); if (collection_data.maximum > 0) { collection_data.supply -= 1; // delete the collection data if the collection supply equals 0 if (collection_data.supply == 0) { destroy_collection_data(collections.collection_data.remove(collection_data.name)); }; }; }; };}
burn
Burn a token by the token owner
public entry fun burn(owner: &signer, creators_address: address, collection: string::String, name: string::String, property_version: u64, amount: u64)
Implementation
public entry fun burn( owner: &signer, creators_address: address, collection: String, name: String, property_version: u64, amount: u64) acquires Collections, TokenStore { assert!(amount > 0, error::invalid_argument(ENO_BURN_TOKEN_WITH_ZERO_AMOUNT)); let token_id = create_token_id_raw(creators_address, collection, name, property_version); let creator_addr = token_id.token_data_id.creator; assert!( exists<Collections>(creator_addr), error::not_found(ECOLLECTIONS_NOT_PUBLISHED), );
let collections = &mut Collections[creator_addr]; assert!( collections.token_data.contains(token_id.token_data_id), error::not_found(ETOKEN_DATA_NOT_PUBLISHED), );
let token_data = collections.token_data.borrow_mut(token_id.token_data_id);
assert!( token_data.default_properties.contains_key(&string::utf8(BURNABLE_BY_OWNER)), error::permission_denied(EOWNER_CANNOT_BURN_TOKEN) ); let burn_by_owner_flag = token_data.default_properties.read_bool(&string::utf8(BURNABLE_BY_OWNER)); assert!(burn_by_owner_flag, error::permission_denied(EOWNER_CANNOT_BURN_TOKEN));
// Burn the tokens. let Token { id: _, amount: burned_amount, token_properties: _ } = withdraw_token(owner, token_id, amount); let token_store = &mut TokenStore[signer::address_of(owner)]; if (std::features::module_event_migration_enabled()) { event::emit(Burn { account: signer::address_of(owner), id: token_id, amount: burned_amount }); } else { event::emit_event<BurnTokenEvent>( &mut token_store.burn_events, BurnTokenEvent { id: token_id, amount: burned_amount } ); };
// Decrease the supply correspondingly by the amount of tokens burned. let token_data = collections.token_data.borrow_mut(token_id.token_data_id);
// only update the supply if we tracking the supply and maximal // maximal == 0 is reserved for unlimited token and collection with no tracking info. if (token_data.maximum > 0) { token_data.supply -= burned_amount;
// Delete the token_data if supply drops to 0. if (token_data.supply == 0) { destroy_token_data(collections.token_data.remove(token_id.token_data_id));
// update the collection supply let collection_data = collections.collection_data.borrow_mut(token_id.token_data_id.collection);
// only update and check the supply for unlimited collection if (collection_data.maximum > 0){ collection_data.supply -= 1; // delete the collection data if the collection supply equals 0 if (collection_data.supply == 0) { destroy_collection_data(collections.collection_data.remove(collection_data.name)); }; }; }; };}
mutate_collection_description
public fun mutate_collection_description(creator: &signer, collection_name: string::String, description: string::String)
Implementation
public fun mutate_collection_description(creator: &signer, collection_name: String, description: String) acquires Collections { let creator_address = signer::address_of(creator); assert_collection_exists(creator_address, collection_name); let collection_data = Collections[creator_address].collection_data.borrow_mut( collection_name ); assert!(collection_data.mutability_config.description, error::permission_denied(EFIELD_NOT_MUTABLE)); token_event_store::emit_collection_description_mutate_event(creator, collection_name, collection_data.description, description); collection_data.description = description;}
mutate_collection_uri
public fun mutate_collection_uri(creator: &signer, collection_name: string::String, uri: string::String)
Implementation
public fun mutate_collection_uri(creator: &signer, collection_name: String, uri: String) acquires Collections { assert!(uri.length() <= MAX_URI_LENGTH, error::invalid_argument(EURI_TOO_LONG)); let creator_address = signer::address_of(creator); assert_collection_exists(creator_address, collection_name); let collection_data = Collections[creator_address].collection_data.borrow_mut( collection_name ); assert!(collection_data.mutability_config.uri, error::permission_denied(EFIELD_NOT_MUTABLE)); token_event_store::emit_collection_uri_mutate_event(creator, collection_name, collection_data.uri , uri); collection_data.uri = uri;}
mutate_collection_maximum
public fun mutate_collection_maximum(creator: &signer, collection_name: string::String, maximum: u64)
Implementation
public fun mutate_collection_maximum(creator: &signer, collection_name: String, maximum: u64) acquires Collections { let creator_address = signer::address_of(creator); assert_collection_exists(creator_address, collection_name); let collection_data = Collections[creator_address].collection_data.borrow_mut( collection_name ); // cannot change maximum from 0 and cannot change maximum to 0 assert!(collection_data.maximum != 0 && maximum != 0, error::invalid_argument(EINVALID_MAXIMUM)); assert!(maximum >= collection_data.supply, error::invalid_argument(EINVALID_MAXIMUM)); assert!(collection_data.mutability_config.maximum, error::permission_denied(EFIELD_NOT_MUTABLE)); token_event_store::emit_collection_maximum_mutate_event(creator, collection_name, collection_data.maximum, maximum); collection_data.maximum = maximum;}
mutate_tokendata_maximum
public fun mutate_tokendata_maximum(creator: &signer, token_data_id: token::TokenDataId, maximum: u64)
Implementation
public fun mutate_tokendata_maximum(creator: &signer, token_data_id: TokenDataId, maximum: u64) acquires Collections { assert_tokendata_exists(creator, token_data_id); let all_token_data = &mut Collections[token_data_id.creator].token_data; let token_data = all_token_data.borrow_mut(token_data_id); // cannot change maximum from 0 and cannot change maximum to 0 assert!(token_data.maximum != 0 && maximum != 0, error::invalid_argument(EINVALID_MAXIMUM)); assert!(maximum >= token_data.supply, error::invalid_argument(EINVALID_MAXIMUM)); assert!(token_data.mutability_config.maximum, error::permission_denied(EFIELD_NOT_MUTABLE)); token_event_store::emit_token_maximum_mutate_event(creator, token_data_id.collection, token_data_id.name, token_data.maximum, maximum); token_data.maximum = maximum;}
mutate_tokendata_uri
public fun mutate_tokendata_uri(creator: &signer, token_data_id: token::TokenDataId, uri: string::String)
Implementation
public fun mutate_tokendata_uri( creator: &signer, token_data_id: TokenDataId, uri: String) acquires Collections { assert!(uri.length() <= MAX_URI_LENGTH, error::invalid_argument(EURI_TOO_LONG)); assert_tokendata_exists(creator, token_data_id);
let all_token_data = &mut Collections[token_data_id.creator].token_data; let token_data = all_token_data.borrow_mut(token_data_id); assert!(token_data.mutability_config.uri, error::permission_denied(EFIELD_NOT_MUTABLE)); token_event_store::emit_token_uri_mutate_event(creator, token_data_id.collection, token_data_id.name, token_data.uri ,uri); token_data.uri = uri;}
mutate_tokendata_royalty
public fun mutate_tokendata_royalty(creator: &signer, token_data_id: token::TokenDataId, royalty: token::Royalty)
Implementation
public fun mutate_tokendata_royalty(creator: &signer, token_data_id: TokenDataId, royalty: Royalty) acquires Collections { assert_tokendata_exists(creator, token_data_id);
let all_token_data = &mut Collections[token_data_id.creator].token_data; let token_data = all_token_data.borrow_mut(token_data_id); assert!(token_data.mutability_config.royalty, error::permission_denied(EFIELD_NOT_MUTABLE));
token_event_store::emit_token_royalty_mutate_event( creator, token_data_id.collection, token_data_id.name, token_data.royalty.royalty_points_numerator, token_data.royalty.royalty_points_denominator, token_data.royalty.payee_address, royalty.royalty_points_numerator, royalty.royalty_points_denominator, royalty.payee_address ); token_data.royalty = royalty;}
mutate_tokendata_description
public fun mutate_tokendata_description(creator: &signer, token_data_id: token::TokenDataId, description: string::String)
Implementation
public fun mutate_tokendata_description(creator: &signer, token_data_id: TokenDataId, description: String) acquires Collections { assert_tokendata_exists(creator, token_data_id);
let all_token_data = &mut Collections[token_data_id.creator].token_data; let token_data = all_token_data.borrow_mut(token_data_id); assert!(token_data.mutability_config.description, error::permission_denied(EFIELD_NOT_MUTABLE)); token_event_store::emit_token_descrition_mutate_event(creator, token_data_id.collection, token_data_id.name, token_data.description, description); token_data.description = description;}
mutate_tokendata_property
Allow creator to mutate the default properties in TokenData
public fun mutate_tokendata_property(creator: &signer, token_data_id: token::TokenDataId, keys: vector<string::String>, values: vector<vector<u8>>, types: vector<string::String>)
Implementation
public fun mutate_tokendata_property( creator: &signer, token_data_id: TokenDataId, keys: vector<String>, values: vector<vector<u8>>, types: vector<String>,) acquires Collections { assert_tokendata_exists(creator, token_data_id); let key_len = keys.length(); let val_len = values.length(); let typ_len = types.length(); assert!(key_len == val_len, error::invalid_state(ETOKEN_PROPERTIES_COUNT_NOT_MATCH)); assert!(key_len == typ_len, error::invalid_state(ETOKEN_PROPERTIES_COUNT_NOT_MATCH));
let all_token_data = &mut Collections[token_data_id.creator].token_data; let token_data = all_token_data.borrow_mut(token_data_id); assert!(token_data.mutability_config.properties, error::permission_denied(EFIELD_NOT_MUTABLE)); let old_values: vector<Option<PropertyValue>> = vector::empty(); let new_values: vector<PropertyValue> = vector::empty(); assert_non_standard_reserved_property(&keys); for (i in 0..keys.length()){ let key = keys.borrow(i); let old_pv = if (token_data.default_properties.contains_key(key)) { option::some(*token_data.default_properties.borrow(key)) } else { option::none<PropertyValue>() }; old_values.push_back(old_pv); let new_pv = property_map::create_property_value_raw(values[i], types[i]); new_values.push_back(new_pv); if (old_pv.is_some()) { token_data.default_properties.update_property_value(key, new_pv); } else { token_data.default_properties.add(*key, new_pv); }; }; token_event_store::emit_default_property_mutate_event(creator, token_data_id.collection, token_data_id.name, keys, old_values, new_values);}
mutate_one_token
Mutate the token_properties of one token.
public fun mutate_one_token(account: &signer, token_owner: address, token_id: token::TokenId, keys: vector<string::String>, values: vector<vector<u8>>, types: vector<string::String>): token::TokenId
Implementation
public fun mutate_one_token( account: &signer, token_owner: address, token_id: TokenId, keys: vector<String>, values: vector<vector<u8>>, types: vector<String>,): TokenId acquires Collections, TokenStore { let creator = token_id.token_data_id.creator; assert!(signer::address_of(account) == creator, error::permission_denied(ENO_MUTATE_CAPABILITY)); // validate if the properties is mutable assert!(exists<Collections>(creator), error::not_found(ECOLLECTIONS_NOT_PUBLISHED)); let all_token_data = &mut Collections[ creator ].token_data;
assert!(all_token_data.contains(token_id.token_data_id), error::not_found(ETOKEN_DATA_NOT_PUBLISHED)); let token_data = all_token_data.borrow_mut(token_id.token_data_id);
// if default property is mutatable, token property is always mutable // we only need to check TOKEN_PROPERTY_MUTABLE when default property is immutable if (!token_data.mutability_config.properties) { assert!( token_data.default_properties.contains_key(&string::utf8(TOKEN_PROPERTY_MUTABLE)), error::permission_denied(EFIELD_NOT_MUTABLE) );
let token_prop_mutable = token_data.default_properties.read_bool(&string::utf8(TOKEN_PROPERTY_MUTABLE)); assert!(token_prop_mutable, error::permission_denied(EFIELD_NOT_MUTABLE)); };
// check if the property_version is 0 to determine if we need to update the property_version if (token_id.property_version == 0) { let token = withdraw_with_event_internal(token_owner, token_id, 1); // give a new property_version for each token let cur_property_version = token_data.largest_property_version + 1; let new_token_id = create_token_id(token_id.token_data_id, cur_property_version); let new_token = Token { id: new_token_id, amount: 1, token_properties: token_data.default_properties, }; direct_deposit(token_owner, new_token); update_token_property_internal(token_owner, new_token_id, keys, values, types); if (std::features::module_event_migration_enabled()) { event::emit(MutatePropertyMap { account: token_owner, old_id: token_id, new_id: new_token_id, keys, values, types }); } else { event::emit_event<MutateTokenPropertyMapEvent>( &mut TokenStore[token_owner].mutate_token_property_events, MutateTokenPropertyMapEvent { old_id: token_id, new_id: new_token_id, keys, values, types }, ); };
token_data.largest_property_version = cur_property_version; // burn the orignial property_version 0 token after mutation let Token { id: _, amount: _, token_properties: _ } = token; new_token_id } else { // only 1 copy for the token with property verion bigger than 0 update_token_property_internal(token_owner, token_id, keys, values, types); if (std::features::module_event_migration_enabled()) { event::emit(MutatePropertyMap { account: token_owner, old_id: token_id, new_id: token_id, keys, values, types }); } else { event::emit_event<MutateTokenPropertyMapEvent>( &mut TokenStore[token_owner].mutate_token_property_events, MutateTokenPropertyMapEvent { old_id: token_id, new_id: token_id, keys, values, types }, ); }; token_id }}
create_royalty
public fun create_royalty(royalty_points_numerator: u64, royalty_points_denominator: u64, payee_address: address): token::Royalty
Implementation
public fun create_royalty(royalty_points_numerator: u64, royalty_points_denominator: u64, payee_address: address): Royalty { assert!(royalty_points_numerator <= royalty_points_denominator, error::invalid_argument(EINVALID_ROYALTY_NUMERATOR_DENOMINATOR)); // Question[Orderless]: Is it okay to remove this check to accommodate stateless accounts? // assert!(account::exists_at(payee_address), error::invalid_argument(EROYALTY_PAYEE_ACCOUNT_DOES_NOT_EXIST)); Royalty { royalty_points_numerator, royalty_points_denominator, payee_address }}
deposit_token
Deposit the token balance into the owner’s account and emit an event.
public fun deposit_token(account: &signer, token: token::Token)
Implementation
public fun deposit_token(account: &signer, token: Token) acquires TokenStore { let account_addr = signer::address_of(account); initialize_token_store(account); direct_deposit(account_addr, token)}
direct_deposit_with_opt_in
direct deposit if user opt in direct transfer
public fun direct_deposit_with_opt_in(account_addr: address, token: token::Token)
Implementation
public fun direct_deposit_with_opt_in(account_addr: address, token: Token) acquires TokenStore { let opt_in_transfer = TokenStore[account_addr].direct_transfer; assert!(opt_in_transfer, error::permission_denied(EUSER_NOT_OPT_IN_DIRECT_TRANSFER)); direct_deposit(account_addr, token);}
direct_transfer
public fun direct_transfer(sender: &signer, receiver: &signer, token_id: token::TokenId, amount: u64)
Implementation
public fun direct_transfer( sender: &signer, receiver: &signer, token_id: TokenId, amount: u64,) acquires TokenStore { let token = withdraw_token(sender, token_id, amount); deposit_token(receiver, token);}
initialize_token_store
public fun initialize_token_store(account: &signer)
Implementation
public fun initialize_token_store(account: &signer) { if (!exists<TokenStore>(signer::address_of(account))) { move_to( account, TokenStore { tokens: table::new(), direct_transfer: false, deposit_events: account::new_event_handle<DepositEvent>(account), withdraw_events: account::new_event_handle<WithdrawEvent>(account), burn_events: account::new_event_handle<BurnTokenEvent>(account), mutate_token_property_events: account::new_event_handle<MutateTokenPropertyMapEvent>(account), }, ); }}
merge
public fun merge(dst_token: &mut token::Token, source_token: token::Token)
Implementation
public fun merge(dst_token: &mut Token, source_token: Token) { assert!(&dst_token.id == &source_token.id, error::invalid_argument(EINVALID_TOKEN_MERGE)); dst_token.amount += source_token.amount; let Token { id: _, amount: _, token_properties: _ } = source_token;}
split
public fun split(dst_token: &mut token::Token, amount: u64): token::Token
Implementation
public fun split(dst_token: &mut Token, amount: u64): Token { assert!(dst_token.id.property_version == 0, error::invalid_state(ENFT_NOT_SPLITABLE)); assert!(dst_token.amount > amount, error::invalid_argument(ETOKEN_SPLIT_AMOUNT_LARGER_OR_EQUAL_TO_TOKEN_AMOUNT)); assert!(amount > 0, error::invalid_argument(ETOKEN_CANNOT_HAVE_ZERO_AMOUNT)); dst_token.amount -= amount; Token { id: dst_token.id, amount, token_properties: property_map::empty(), }}
token_id
public fun token_id(token: &token::Token): &token::TokenId
Implementation
public fun token_id(token: &Token): &TokenId { &token.id}
transfer
Transfers amount
of tokens from from
to to
.
public fun transfer(from: &signer, id: token::TokenId, to: address, amount: u64)
Implementation
public fun transfer( from: &signer, id: TokenId, to: address, amount: u64,) acquires TokenStore { let opt_in_transfer = TokenStore[to].direct_transfer; assert!(opt_in_transfer, error::permission_denied(EUSER_NOT_OPT_IN_DIRECT_TRANSFER)); let token = withdraw_token(from, id, amount); direct_deposit(to, token);}
create_withdraw_capability
Token owner can create this one-time withdraw capability with an expiration time
public fun create_withdraw_capability(owner: &signer, token_id: token::TokenId, amount: u64, expiration_sec: u64): token::WithdrawCapability
Implementation
public fun create_withdraw_capability( owner: &signer, token_id: TokenId, amount: u64, expiration_sec: u64,): WithdrawCapability { WithdrawCapability { token_owner: signer::address_of(owner), token_id, amount, expiration_sec, }}
withdraw_with_capability
Withdraw the token with a capability
public fun withdraw_with_capability(withdraw_proof: token::WithdrawCapability): token::Token
Implementation
public fun withdraw_with_capability( withdraw_proof: WithdrawCapability,): Token acquires TokenStore { // verify the delegation hasn't expired yet assert!(timestamp::now_seconds() <= withdraw_proof.expiration_sec, error::invalid_argument(EWITHDRAW_PROOF_EXPIRES));
withdraw_with_event_internal( withdraw_proof.token_owner, withdraw_proof.token_id, withdraw_proof.amount, )}
partial_withdraw_with_capability
Withdraw the token with a capability.
public fun partial_withdraw_with_capability(withdraw_proof: token::WithdrawCapability, withdraw_amount: u64): (token::Token, option::Option<token::WithdrawCapability>)
Implementation
public fun partial_withdraw_with_capability( withdraw_proof: WithdrawCapability, withdraw_amount: u64,): (Token, Option<WithdrawCapability>) acquires TokenStore { // verify the delegation hasn't expired yet assert!(timestamp::now_seconds() <= withdraw_proof.expiration_sec, error::invalid_argument(EWITHDRAW_PROOF_EXPIRES));
assert!(withdraw_amount <= withdraw_proof.amount, error::invalid_argument(EINSUFFICIENT_WITHDRAW_CAPABILITY_AMOUNT));
let res: Option<WithdrawCapability> = if (withdraw_amount == withdraw_proof.amount) { option::none<WithdrawCapability>() } else { option::some( WithdrawCapability { token_owner: withdraw_proof.token_owner, token_id: withdraw_proof.token_id, amount: withdraw_proof.amount - withdraw_amount, expiration_sec: withdraw_proof.expiration_sec, } ) };
( withdraw_with_event_internal( withdraw_proof.token_owner, withdraw_proof.token_id, withdraw_amount, ), res )
}
withdraw_token
public fun withdraw_token(account: &signer, id: token::TokenId, amount: u64): token::Token
Implementation
public fun withdraw_token( account: &signer, id: TokenId, amount: u64,): Token acquires TokenStore { let account_addr = signer::address_of(account); withdraw_with_event_internal(account_addr, id, amount)}
create_collection
Create a new collection to hold tokens
public fun create_collection(creator: &signer, name: string::String, description: string::String, uri: string::String, maximum: u64, mutate_setting: vector<bool>)
Implementation
public fun create_collection( creator: &signer, name: String, description: String, uri: String, maximum: u64, mutate_setting: vector<bool>) acquires Collections { assert!(name.length() <= MAX_COLLECTION_NAME_LENGTH, error::invalid_argument(ECOLLECTION_NAME_TOO_LONG)); assert!(uri.length() <= MAX_URI_LENGTH, error::invalid_argument(EURI_TOO_LONG)); let account_addr = signer::address_of(creator); if (!exists<Collections>(account_addr)) { move_to( creator, Collections { collection_data: table::new(), token_data: table::new(), create_collection_events: account::new_event_handle<CreateCollectionEvent>(creator), create_token_data_events: account::new_event_handle<CreateTokenDataEvent>(creator), mint_token_events: account::new_event_handle<MintTokenEvent>(creator), }, ) };
let collection_data = &mut Collections[account_addr].collection_data;
assert!( !collection_data.contains(name), error::already_exists(ECOLLECTION_ALREADY_EXISTS), );
let mutability_config = create_collection_mutability_config(&mutate_setting); let collection = CollectionData { description, name, uri, supply: 0, maximum, mutability_config };
collection_data.add(name, collection); let collection_handle = &mut Collections[account_addr]; if (std::features::module_event_migration_enabled()) { event::emit( CreateCollection { creator: account_addr, collection_name: name, uri, description, maximum, } ); } else { event::emit_event<CreateCollectionEvent>( &mut collection_handle.create_collection_events, CreateCollectionEvent { creator: account_addr, collection_name: name, uri, description, maximum, } ); };}
check_collection_exists
public fun check_collection_exists(creator: address, name: string::String): bool
Implementation
public fun check_collection_exists(creator: address, name: String): bool acquires Collections { assert!( exists<Collections>(creator), error::not_found(ECOLLECTIONS_NOT_PUBLISHED), );
let collection_data = &Collections[creator].collection_data; collection_data.contains(name)}
check_tokendata_exists
public fun check_tokendata_exists(creator: address, collection_name: string::String, token_name: string::String): bool
Implementation
public fun check_tokendata_exists(creator: address, collection_name: String, token_name: String): bool acquires Collections { assert!( exists<Collections>(creator), error::not_found(ECOLLECTIONS_NOT_PUBLISHED), );
let token_data = &Collections[creator].token_data; let token_data_id = create_token_data_id(creator, collection_name, token_name); token_data.contains(token_data_id)}
create_tokendata
public fun create_tokendata(account: &signer, collection: string::String, name: string::String, description: string::String, maximum: u64, uri: string::String, royalty_payee_address: address, royalty_points_denominator: u64, royalty_points_numerator: u64, token_mutate_config: token::TokenMutabilityConfig, property_keys: vector<string::String>, property_values: vector<vector<u8>>, property_types: vector<string::String>): token::TokenDataId
Implementation
public fun create_tokendata( account: &signer, collection: String, name: String, description: String, maximum: u64, uri: String, royalty_payee_address: address, royalty_points_denominator: u64, royalty_points_numerator: u64, token_mutate_config: TokenMutabilityConfig, property_keys: vector<String>, property_values: vector<vector<u8>>, property_types: vector<String>): TokenDataId acquires Collections { assert!(name.length() <= MAX_NFT_NAME_LENGTH, error::invalid_argument(ENFT_NAME_TOO_LONG)); assert!(collection.length() <= MAX_COLLECTION_NAME_LENGTH, error::invalid_argument(ECOLLECTION_NAME_TOO_LONG)); assert!(uri.length() <= MAX_URI_LENGTH, error::invalid_argument(EURI_TOO_LONG)); assert!(royalty_points_numerator <= royalty_points_denominator, error::invalid_argument(EINVALID_ROYALTY_NUMERATOR_DENOMINATOR));
let account_addr = signer::address_of(account); assert!( exists<Collections>(account_addr), error::not_found(ECOLLECTIONS_NOT_PUBLISHED), ); let collections = &mut Collections[account_addr];
let token_data_id = create_token_data_id(account_addr, collection, name);
assert!( collections.collection_data.contains(token_data_id.collection), error::not_found(ECOLLECTION_NOT_PUBLISHED), ); assert!( !collections.token_data.contains(token_data_id), error::already_exists(ETOKEN_DATA_ALREADY_EXISTS), );
let collection = collections.collection_data.borrow_mut(token_data_id.collection);
// if collection maximum == 0, user don't want to enforce supply constraint. // we don't track supply to make token creation parallelizable if (collection.maximum > 0) { collection.supply += 1; assert!( collection.maximum >= collection.supply, error::invalid_argument(ECREATE_WOULD_EXCEED_COLLECTION_MAXIMUM), ); };
let token_data = TokenData { maximum, largest_property_version: 0, supply: 0, uri, royalty: create_royalty(royalty_points_numerator, royalty_points_denominator, royalty_payee_address), name, description, default_properties: property_map::new(property_keys, property_values, property_types), mutability_config: token_mutate_config, };
collections.token_data.add(token_data_id, token_data); if (std::features::module_event_migration_enabled()) { event::emit( TokenDataCreation { creator: account_addr, id: token_data_id, description, maximum, uri, royalty_payee_address, royalty_points_denominator, royalty_points_numerator, name, mutability_config: token_mutate_config, property_keys, property_values, property_types, } ); } else { event::emit_event<CreateTokenDataEvent>( &mut collections.create_token_data_events, CreateTokenDataEvent { id: token_data_id, description, maximum, uri, royalty_payee_address, royalty_points_denominator, royalty_points_numerator, name, mutability_config: token_mutate_config, property_keys, property_values, property_types, }, ); };
token_data_id}
get_collection_supply
return the number of distinct token_data_id created under this collection
public fun get_collection_supply(creator_address: address, collection_name: string::String): option::Option<u64>
Implementation
public fun get_collection_supply(creator_address: address, collection_name: String): Option<u64> acquires Collections { assert_collection_exists(creator_address, collection_name); let collection_data = Collections[creator_address].collection_data.borrow_mut( collection_name );
if (collection_data.maximum > 0) { option::some(collection_data.supply) } else { option::none() }}
get_collection_description
public fun get_collection_description(creator_address: address, collection_name: string::String): string::String
Implementation
public fun get_collection_description(creator_address: address, collection_name: String): String acquires Collections { assert_collection_exists(creator_address, collection_name); let collection_data = Collections[creator_address].collection_data.borrow_mut( collection_name ); collection_data.description}
get_collection_uri
public fun get_collection_uri(creator_address: address, collection_name: string::String): string::String
Implementation
public fun get_collection_uri(creator_address: address, collection_name: String): String acquires Collections { assert_collection_exists(creator_address, collection_name); let collection_data = Collections[creator_address].collection_data.borrow_mut( collection_name ); collection_data.uri}
get_collection_maximum
public fun get_collection_maximum(creator_address: address, collection_name: string::String): u64
Implementation
public fun get_collection_maximum(creator_address: address, collection_name: String): u64 acquires Collections { assert_collection_exists(creator_address, collection_name); let collection_data = Collections[creator_address].collection_data.borrow_mut( collection_name ); collection_data.maximum}
get_token_supply
return the number of distinct token_id created under this TokenData
public fun get_token_supply(creator_address: address, token_data_id: token::TokenDataId): option::Option<u64>
Implementation
public fun get_token_supply(creator_address: address, token_data_id: TokenDataId): Option<u64> acquires Collections { assert!(exists<Collections>(creator_address), error::not_found(ECOLLECTIONS_NOT_PUBLISHED)); let all_token_data = &Collections[creator_address].token_data; assert!(all_token_data.contains(token_data_id), error::not_found(ETOKEN_DATA_NOT_PUBLISHED)); let token_data = all_token_data.borrow(token_data_id);
if (token_data.maximum > 0) { option::some(token_data.supply) } else { option::none<u64>() }}
get_tokendata_largest_property_version
return the largest_property_version of this TokenData
public fun get_tokendata_largest_property_version(creator_address: address, token_data_id: token::TokenDataId): u64
Implementation
public fun get_tokendata_largest_property_version(creator_address: address, token_data_id: TokenDataId): u64 acquires Collections { assert!(exists<Collections>(creator_address), error::not_found(ECOLLECTIONS_NOT_PUBLISHED)); let all_token_data = &Collections[creator_address].token_data; assert!(all_token_data.contains(token_data_id), error::not_found(ETOKEN_DATA_NOT_PUBLISHED)); all_token_data.borrow(token_data_id).largest_property_version}
get_token_id
return the TokenId for a given Token
public fun get_token_id(token: &token::Token): token::TokenId
Implementation
public fun get_token_id(token: &Token): TokenId { token.id}
get_direct_transfer
public fun get_direct_transfer(receiver: address): bool
Implementation
public fun get_direct_transfer(receiver: address): bool acquires TokenStore { if (!exists<TokenStore>(receiver)) { return false };
TokenStore[receiver].direct_transfer}
create_token_mutability_config
public fun create_token_mutability_config(mutate_setting: &vector<bool>): token::TokenMutabilityConfig
Implementation
public fun create_token_mutability_config(mutate_setting: &vector<bool>): TokenMutabilityConfig { TokenMutabilityConfig { maximum: mutate_setting[TOKEN_MAX_MUTABLE_IND], uri: mutate_setting[TOKEN_URI_MUTABLE_IND], royalty: mutate_setting[TOKEN_ROYALTY_MUTABLE_IND], description: mutate_setting[TOKEN_DESCRIPTION_MUTABLE_IND], properties: mutate_setting[TOKEN_PROPERTY_MUTABLE_IND], }}
create_collection_mutability_config
public fun create_collection_mutability_config(mutate_setting: &vector<bool>): token::CollectionMutabilityConfig
Implementation
public fun create_collection_mutability_config(mutate_setting: &vector<bool>): CollectionMutabilityConfig { CollectionMutabilityConfig { description: mutate_setting[COLLECTION_DESCRIPTION_MUTABLE_IND], uri: mutate_setting[COLLECTION_URI_MUTABLE_IND], maximum: mutate_setting[COLLECTION_MAX_MUTABLE_IND], }}
mint_token
public fun mint_token(account: &signer, token_data_id: token::TokenDataId, amount: u64): token::TokenId
Implementation
public fun mint_token( account: &signer, token_data_id: TokenDataId, amount: u64,): TokenId acquires Collections, TokenStore { assert!(token_data_id.creator == signer::address_of(account), error::permission_denied(ENO_MINT_CAPABILITY)); let creator_addr = token_data_id.creator; let all_token_data = &mut Collections[creator_addr].token_data; assert!(all_token_data.contains(token_data_id), error::not_found(ETOKEN_DATA_NOT_PUBLISHED)); let token_data = all_token_data.borrow_mut(token_data_id);
if (token_data.maximum > 0) { assert!(token_data.supply + amount <= token_data.maximum, error::invalid_argument(EMINT_WOULD_EXCEED_TOKEN_MAXIMUM)); token_data.supply += amount; };
// we add more tokens with property_version 0 let token_id = create_token_id(token_data_id, 0); if (std::features::module_event_migration_enabled()) { event::emit(Mint { creator: creator_addr, id: token_data_id, amount }) } else { event::emit_event<MintTokenEvent>( &mut Collections[creator_addr].mint_token_events, MintTokenEvent { id: token_data_id, amount, } ); };
deposit_token(account, Token { id: token_id, amount, token_properties: property_map::empty(), // same as default properties no need to store } );
token_id}
mint_token_to
create tokens and directly deposite to receiver’s address. The receiver should opt-in direct transfer
public fun mint_token_to(account: &signer, receiver: address, token_data_id: token::TokenDataId, amount: u64)
Implementation
public fun mint_token_to( account: &signer, receiver: address, token_data_id: TokenDataId, amount: u64,) acquires Collections, TokenStore { assert!(exists<TokenStore>(receiver), error::not_found(ETOKEN_STORE_NOT_PUBLISHED)); let opt_in_transfer = TokenStore[receiver].direct_transfer; assert!(opt_in_transfer, error::permission_denied(EUSER_NOT_OPT_IN_DIRECT_TRANSFER));
assert!(token_data_id.creator == signer::address_of(account), error::permission_denied(ENO_MINT_CAPABILITY)); let creator_addr = token_data_id.creator; let all_token_data = &mut Collections[creator_addr].token_data; assert!(all_token_data.contains(token_data_id), error::not_found(ETOKEN_DATA_NOT_PUBLISHED)); let token_data = all_token_data.borrow_mut(token_data_id);
if (token_data.maximum > 0) { assert!(token_data.supply + amount <= token_data.maximum, error::invalid_argument(EMINT_WOULD_EXCEED_TOKEN_MAXIMUM)); token_data.supply += amount; };
// we add more tokens with property_version 0 let token_id = create_token_id(token_data_id, 0);
if (std::features::module_event_migration_enabled()) { event::emit(Mint { creator: creator_addr, id: token_data_id, amount }) } else { event::emit_event<MintTokenEvent>( &mut Collections[creator_addr].mint_token_events, MintTokenEvent { id: token_data_id, amount, } ); };
direct_deposit(receiver, Token { id: token_id, amount, token_properties: property_map::empty(), // same as default properties no need to store } );}
create_token_id
public fun create_token_id(token_data_id: token::TokenDataId, property_version: u64): token::TokenId
Implementation
public fun create_token_id(token_data_id: TokenDataId, property_version: u64): TokenId { TokenId { token_data_id, property_version, }}
create_token_data_id
public fun create_token_data_id(creator: address, collection: string::String, name: string::String): token::TokenDataId
Implementation
public fun create_token_data_id( creator: address, collection: String, name: String,): TokenDataId { assert!(collection.length() <= MAX_COLLECTION_NAME_LENGTH, error::invalid_argument(ECOLLECTION_NAME_TOO_LONG)); assert!(name.length() <= MAX_NFT_NAME_LENGTH, error::invalid_argument(ENFT_NAME_TOO_LONG)); TokenDataId { creator, collection, name }}
create_token_id_raw
public fun create_token_id_raw(creator: address, collection: string::String, name: string::String, property_version: u64): token::TokenId
Implementation
public fun create_token_id_raw( creator: address, collection: String, name: String, property_version: u64,): TokenId { TokenId { token_data_id: create_token_data_id(creator, collection, name), property_version, }}
balance_of
public fun balance_of(owner: address, id: token::TokenId): u64
Implementation
public fun balance_of(owner: address, id: TokenId): u64 acquires TokenStore { if (!exists<TokenStore>(owner)) { return 0 }; let token_store = &TokenStore[owner]; if (token_store.tokens.contains(id)) { token_store.tokens.borrow(id).amount } else { 0 }}
has_token_store
public fun has_token_store(owner: address): bool
Implementation
public fun has_token_store(owner: address): bool { exists<TokenStore>(owner)}
get_royalty
public fun get_royalty(token_id: token::TokenId): token::Royalty
Implementation
public fun get_royalty(token_id: TokenId): Royalty acquires Collections { let token_data_id = token_id.token_data_id; get_tokendata_royalty(token_data_id)}
get_royalty_numerator
public fun get_royalty_numerator(royalty: &token::Royalty): u64
Implementation
public fun get_royalty_numerator(royalty: &Royalty): u64 { royalty.royalty_points_numerator}
get_royalty_denominator
public fun get_royalty_denominator(royalty: &token::Royalty): u64
Implementation
public fun get_royalty_denominator(royalty: &Royalty): u64 { royalty.royalty_points_denominator}
get_royalty_payee
public fun get_royalty_payee(royalty: &token::Royalty): address
Implementation
public fun get_royalty_payee(royalty: &Royalty): address { royalty.payee_address}
get_token_amount
public fun get_token_amount(token: &token::Token): u64
Implementation
public fun get_token_amount(token: &Token): u64 { token.amount}
get_token_id_fields
return the creator address, collection name, token name and property_version
public fun get_token_id_fields(token_id: &token::TokenId): (address, string::String, string::String, u64)
Implementation
public fun get_token_id_fields(token_id: &TokenId): (address, String, String, u64) { ( token_id.token_data_id.creator, token_id.token_data_id.collection, token_id.token_data_id.name, token_id.property_version, )}
get_token_data_id_fields
public fun get_token_data_id_fields(token_data_id: &token::TokenDataId): (address, string::String, string::String)
Implementation
public fun get_token_data_id_fields(token_data_id: &TokenDataId): (address, String, String) { ( token_data_id.creator, token_data_id.collection, token_data_id.name, )}
get_property_map
return a copy of the token property map. if property_version = 0, return the default property map if property_version > 0, return the property value stored at owner’s token store
public fun get_property_map(owner: address, token_id: token::TokenId): property_map::PropertyMap
Implementation
public fun get_property_map(owner: address, token_id: TokenId): PropertyMap acquires Collections, TokenStore { assert!(balance_of(owner, token_id) > 0, error::not_found(EINSUFFICIENT_BALANCE)); // if property_version = 0, return default property map if (token_id.property_version == 0) { let creator_addr = token_id.token_data_id.creator; let all_token_data = &Collections[creator_addr].token_data; assert!(all_token_data.contains(token_id.token_data_id), error::not_found(ETOKEN_DATA_NOT_PUBLISHED)); let token_data = all_token_data.borrow(token_id.token_data_id); token_data.default_properties } else { let tokens = &TokenStore[owner].tokens; tokens.borrow(token_id).token_properties }}
get_tokendata_maximum
public fun get_tokendata_maximum(token_data_id: token::TokenDataId): u64
Implementation
public fun get_tokendata_maximum(token_data_id: TokenDataId): u64 acquires Collections { let creator_address = token_data_id.creator; assert!(exists<Collections>(creator_address), error::not_found(ECOLLECTIONS_NOT_PUBLISHED)); let all_token_data = &Collections[creator_address].token_data; assert!(all_token_data.contains(token_data_id), error::not_found(ETOKEN_DATA_NOT_PUBLISHED));
let token_data = all_token_data.borrow(token_data_id); token_data.maximum}
get_tokendata_uri
public fun get_tokendata_uri(creator: address, token_data_id: token::TokenDataId): string::String
Implementation
public fun get_tokendata_uri(creator: address, token_data_id: TokenDataId): String acquires Collections { assert!(exists<Collections>(creator), error::not_found(ECOLLECTIONS_NOT_PUBLISHED)); let all_token_data = &Collections[creator].token_data; assert!(all_token_data.contains(token_data_id), error::not_found(ETOKEN_DATA_NOT_PUBLISHED));
let token_data = all_token_data.borrow(token_data_id); token_data.uri}
get_tokendata_description
public fun get_tokendata_description(token_data_id: token::TokenDataId): string::String
Implementation
public fun get_tokendata_description(token_data_id: TokenDataId): String acquires Collections { let creator_address = token_data_id.creator; assert!(exists<Collections>(creator_address), error::not_found(ECOLLECTIONS_NOT_PUBLISHED)); let all_token_data = &Collections[creator_address].token_data; assert!(all_token_data.contains(token_data_id), error::not_found(ETOKEN_DATA_NOT_PUBLISHED));
let token_data = all_token_data.borrow(token_data_id); token_data.description}
get_tokendata_royalty
public fun get_tokendata_royalty(token_data_id: token::TokenDataId): token::Royalty
Implementation
public fun get_tokendata_royalty(token_data_id: TokenDataId): Royalty acquires Collections { let creator_address = token_data_id.creator; assert!(exists<Collections>(creator_address), error::not_found(ECOLLECTIONS_NOT_PUBLISHED)); let all_token_data = &Collections[creator_address].token_data; assert!(all_token_data.contains(token_data_id), error::not_found(ETOKEN_DATA_NOT_PUBLISHED));
let token_data = all_token_data.borrow(token_data_id); token_data.royalty}
get_tokendata_id
return the token_data_id from the token_id
public fun get_tokendata_id(token_id: token::TokenId): token::TokenDataId
Implementation
public fun get_tokendata_id(token_id: TokenId): TokenDataId { token_id.token_data_id}
get_tokendata_mutability_config
return the mutation setting of the token
public fun get_tokendata_mutability_config(token_data_id: token::TokenDataId): token::TokenMutabilityConfig
Implementation
public fun get_tokendata_mutability_config(token_data_id: TokenDataId): TokenMutabilityConfig acquires Collections { let creator_addr = token_data_id.creator; assert!(exists<Collections>(creator_addr), error::not_found(ECOLLECTIONS_NOT_PUBLISHED)); let all_token_data = &Collections[creator_addr].token_data; assert!(all_token_data.contains(token_data_id), error::not_found(ETOKEN_DATA_NOT_PUBLISHED)); all_token_data.borrow(token_data_id).mutability_config}
get_token_mutability_maximum
return if the token’s maximum is mutable
public fun get_token_mutability_maximum(config: &token::TokenMutabilityConfig): bool
Implementation
public fun get_token_mutability_maximum(config: &TokenMutabilityConfig): bool { config.maximum}
get_token_mutability_royalty
return if the token royalty is mutable with a token mutability config
public fun get_token_mutability_royalty(config: &token::TokenMutabilityConfig): bool
Implementation
public fun get_token_mutability_royalty(config: &TokenMutabilityConfig): bool { config.royalty}
get_token_mutability_uri
return if the token uri is mutable with a token mutability config
public fun get_token_mutability_uri(config: &token::TokenMutabilityConfig): bool
Implementation
public fun get_token_mutability_uri(config: &TokenMutabilityConfig): bool { config.uri}
get_token_mutability_description
return if the token description is mutable with a token mutability config
public fun get_token_mutability_description(config: &token::TokenMutabilityConfig): bool
Implementation
public fun get_token_mutability_description(config: &TokenMutabilityConfig): bool { config.description}
get_token_mutability_default_properties
return if the tokendata’s default properties is mutable with a token mutability config
public fun get_token_mutability_default_properties(config: &token::TokenMutabilityConfig): bool
Implementation
public fun get_token_mutability_default_properties(config: &TokenMutabilityConfig): bool { config.properties}
get_collection_mutability_config
return the collection mutation setting
#[view]public fun get_collection_mutability_config(creator: address, collection_name: string::String): token::CollectionMutabilityConfig
Implementation
public fun get_collection_mutability_config( creator: address, collection_name: String): CollectionMutabilityConfig acquires Collections { assert!(exists<Collections>(creator), error::not_found(ECOLLECTIONS_NOT_PUBLISHED)); let all_collection_data = &Collections[creator].collection_data; assert!(all_collection_data.contains(collection_name), error::not_found(ECOLLECTION_NOT_PUBLISHED)); all_collection_data.borrow(collection_name).mutability_config}
get_collection_mutability_description
return if the collection description is mutable with a collection mutability config
public fun get_collection_mutability_description(config: &token::CollectionMutabilityConfig): bool
Implementation
public fun get_collection_mutability_description(config: &CollectionMutabilityConfig): bool { config.description}
get_collection_mutability_uri
return if the collection uri is mutable with a collection mutability config
public fun get_collection_mutability_uri(config: &token::CollectionMutabilityConfig): bool
Implementation
public fun get_collection_mutability_uri(config: &CollectionMutabilityConfig): bool { config.uri}
get_collection_mutability_maximum
return if the collection maximum is mutable with collection mutability config
public fun get_collection_mutability_maximum(config: &token::CollectionMutabilityConfig): bool
Implementation
public fun get_collection_mutability_maximum(config: &CollectionMutabilityConfig): bool { config.maximum}
destroy_token_data
fun destroy_token_data(token_data: token::TokenData)
Implementation
fun destroy_token_data(token_data: TokenData) { let TokenData { maximum: _, largest_property_version: _, supply: _, uri: _, royalty: _, name: _, description: _, default_properties: _, mutability_config: _, } = token_data;}
destroy_collection_data
fun destroy_collection_data(collection_data: token::CollectionData)
Implementation
fun destroy_collection_data(collection_data: CollectionData) { let CollectionData { description: _, name: _, uri: _, supply: _, maximum: _, mutability_config: _, } = collection_data;}
withdraw_with_event_internal
fun withdraw_with_event_internal(account_addr: address, id: token::TokenId, amount: u64): token::Token
Implementation
fun withdraw_with_event_internal( account_addr: address, id: TokenId, amount: u64,): Token acquires TokenStore { // It does not make sense to withdraw 0 tokens. assert!(amount > 0, error::invalid_argument(EWITHDRAW_ZERO)); // Make sure the account has sufficient tokens to withdraw. assert!(balance_of(account_addr, id) >= amount, error::invalid_argument(EINSUFFICIENT_BALANCE));
assert!( exists<TokenStore>(account_addr), error::not_found(ETOKEN_STORE_NOT_PUBLISHED), );
let token_store = &mut TokenStore[account_addr]; if (std::features::module_event_migration_enabled()) { event::emit(TokenWithdraw { account: account_addr, id, amount }) } else { event::emit_event<WithdrawEvent>( &mut token_store.withdraw_events, WithdrawEvent { id, amount } ); };
let tokens = &mut TokenStore[account_addr].tokens; assert!( tokens.contains(id), error::not_found(ENO_TOKEN_IN_TOKEN_STORE), ); // balance > amount and amount > 0 indirectly asserted that balance > 0. let balance = &mut tokens.borrow_mut(id).amount; if (*balance > amount) { *balance -= amount; Token { id, amount, token_properties: property_map::empty() } } else { tokens.remove(id) }}
update_token_property_internal
fun update_token_property_internal(token_owner: address, token_id: token::TokenId, keys: vector<string::String>, values: vector<vector<u8>>, types: vector<string::String>)
Implementation
fun update_token_property_internal( token_owner: address, token_id: TokenId, keys: vector<String>, values: vector<vector<u8>>, types: vector<String>,) acquires TokenStore { let tokens = &mut TokenStore[token_owner].tokens; assert!(tokens.contains(token_id), error::not_found(ENO_TOKEN_IN_TOKEN_STORE));
let value = &mut tokens.borrow_mut(token_id).token_properties; assert_non_standard_reserved_property(&keys); value.update_property_map(keys, values, types);}
direct_deposit
Deposit the token balance into the recipients account and emit an event.
fun direct_deposit(account_addr: address, token: token::Token)
Implementation
fun direct_deposit(account_addr: address, token: Token) acquires TokenStore { assert!(token.amount > 0, error::invalid_argument(ETOKEN_CANNOT_HAVE_ZERO_AMOUNT)); let token_store = &mut TokenStore[account_addr];
if (std::features::module_event_migration_enabled()) { event::emit(TokenDeposit { account: account_addr, id: token.id, amount: token.amount }); } else { event::emit_event<DepositEvent>( &mut token_store.deposit_events, DepositEvent { id: token.id, amount: token.amount }, ); };
assert!( exists<TokenStore>(account_addr), error::not_found(ETOKEN_STORE_NOT_PUBLISHED), );
if (!token_store.tokens.contains(token.id)) { token_store.tokens.add(token.id, token); } else { let recipient_token = token_store.tokens.borrow_mut(token.id); merge(recipient_token, token); };}
assert_collection_exists
fun assert_collection_exists(creator_address: address, collection_name: string::String)
Implementation
fun assert_collection_exists(creator_address: address, collection_name: String) acquires Collections { assert!(exists<Collections>(creator_address), error::not_found(ECOLLECTIONS_NOT_PUBLISHED)); let all_collection_data = &Collections[creator_address].collection_data; assert!(all_collection_data.contains(collection_name), error::not_found(ECOLLECTION_NOT_PUBLISHED));}
assert_tokendata_exists
fun assert_tokendata_exists(creator: &signer, token_data_id: token::TokenDataId)
Implementation
fun assert_tokendata_exists(creator: &signer, token_data_id: TokenDataId) acquires Collections { let creator_addr = token_data_id.creator; assert!(signer::address_of(creator) == creator_addr, error::permission_denied(ENO_MUTATE_CAPABILITY)); assert!(exists<Collections>(creator_addr), error::not_found(ECOLLECTIONS_NOT_PUBLISHED)); let all_token_data = &Collections[creator_addr].token_data; assert!(all_token_data.contains(token_data_id), error::not_found(ETOKEN_DATA_NOT_PUBLISHED));}
assert_non_standard_reserved_property
fun assert_non_standard_reserved_property(keys: &vector<string::String>)
Implementation
fun assert_non_standard_reserved_property(keys: &vector<String>) { keys.for_each_ref(|key| { let key: &String = key; let length = key.length(); if (length >= 6) { let prefix = key.sub_string(0, 6); assert!(prefix != string::utf8(b"TOKEN_"), error::permission_denied(EPROPERTY_RESERVED_BY_STANDARD)); }; });}
initialize_token_script
public entry fun initialize_token_script(_account: &signer)
Implementation
public entry fun initialize_token_script(_account: &signer) { abort 0}
initialize_token
public fun initialize_token(_account: &signer, _token_id: token::TokenId)
Implementation
public fun initialize_token(_account: &signer, _token_id: TokenId) { abort 0}
Specification
pragma verify = true;pragma aborts_if_is_partial;
create_collection_script
public entry fun create_collection_script(creator: &signer, name: string::String, description: string::String, uri: string::String, maximum: u64, mutate_setting: vector<bool>)
The length of the name is up to MAX_COLLECTION_NAME_LENGTH; The length of the uri is up to MAX_URI_LENGTH;
pragma aborts_if_is_partial;include CreateCollectionAbortsIf;
create_token_script
public entry fun create_token_script(account: &signer, collection: string::String, name: string::String, description: string::String, balance: u64, maximum: u64, uri: string::String, royalty_payee_address: address, royalty_points_denominator: u64, royalty_points_numerator: u64, mutate_setting: vector<bool>, property_keys: vector<string::String>, property_values: vector<vector<u8>>, property_types: vector<string::String>)
the length of ‘mutate_setting’ should maore than five. The creator of the TokenDataId is signer. The token_data_id should exist in the creator’s collections.. The sum of supply and mint Token is less than maximum.
pragma aborts_if_is_partial;let addr = signer::address_of(account);let token_data_id = spec_create_tokendata(addr, collection, name);let creator_addr = token_data_id.creator;let all_token_data = global<Collections>(creator_addr).token_data;let token_data = table::spec_get(all_token_data, token_data_id);aborts_if token_data_id.creator != addr;aborts_if !exists<Collections>(creator_addr);aborts_if balance <= 0;include CreateTokenMutabilityConfigAbortsIf;include CreateTokenMutabilityConfigAbortsIf;
fun spec_create_tokendata( creator: address, collection: String, name: String): TokenDataId { TokenDataId { creator, collection, name }}
mint_script
public entry fun mint_script(account: &signer, token_data_address: address, collection: string::String, name: string::String, amount: u64)
only creator of the tokendata can mint tokens
pragma aborts_if_is_partial;let token_data_id = spec_create_token_data_id( token_data_address, collection, name,);let addr = signer::address_of(account);let creator_addr = token_data_id.creator;let all_token_data = global<Collections>(creator_addr).token_data;let token_data = table::spec_get(all_token_data, token_data_id);aborts_if token_data_id.creator != signer::address_of(account);include CreateTokenDataIdAbortsIf{creator: token_data_address,collection,name};include MintTokenAbortsIf {token_data_id};
mutate_token_properties
public entry fun mutate_token_properties(account: &signer, token_owner: address, creator: address, collection_name: string::String, token_name: string::String, token_property_version: u64, amount: u64, keys: vector<string::String>, values: vector<vector<u8>>, types: vector<string::String>)
The signer is creator.
pragma aborts_if_is_partial;let addr = signer::address_of(account);aborts_if addr != creator;include CreateTokenDataIdAbortsIf { creator, collection: collection_name, name: token_name};
direct_transfer_script
public entry fun direct_transfer_script(sender: &signer, receiver: &signer, creators_address: address, collection: string::String, name: string::String, property_version: u64, amount: u64)
pragma aborts_if_is_partial;include CreateTokenDataIdAbortsIf{ creator: creators_address, collection, name};
opt_in_direct_transfer
public entry fun opt_in_direct_transfer(account: &signer, opt_in: bool)
pragma aborts_if_is_partial;let addr = signer::address_of(account);let account_addr = global<account::Account>(addr);
transfer_with_opt_in
public entry fun transfer_with_opt_in(from: &signer, creator: address, collection_name: string::String, token_name: string::String, token_property_version: u64, to: address, amount: u64)
pragma aborts_if_is_partial;include CreateTokenDataIdAbortsIf{ creator, collection: collection_name, name: token_name};
burn_by_creator
public entry fun burn_by_creator(creator: &signer, owner: address, collection: string::String, name: string::String, property_version: u64, amount: u64)
pragma aborts_if_is_partial;let creator_address = signer::address_of(creator);let token_id = spec_create_token_id_raw(creator_address, collection, name, property_version);let creator_addr = token_id.token_data_id.creator;let collections = borrow_global_mut<Collections>(creator_address);let token_data = table::spec_get( collections.token_data, token_id.token_data_id,);aborts_if amount <= 0;aborts_if !exists<Collections>(creator_addr);aborts_if !table::spec_contains(collections.token_data, token_id.token_data_id);aborts_if !simple_map::spec_contains_key(token_data.default_properties.map, std::string::spec_utf8(BURNABLE_BY_CREATOR));
burn
public entry fun burn(owner: &signer, creators_address: address, collection: string::String, name: string::String, property_version: u64, amount: u64)
The token_data_id should exist in token_data.
pragma aborts_if_is_partial;let token_id = spec_create_token_id_raw(creators_address, collection, name, property_version);let creator_addr = token_id.token_data_id.creator;let collections = borrow_global_mut<Collections>(creator_addr);let token_data = table::spec_get( collections.token_data, token_id.token_data_id,);include CreateTokenDataIdAbortsIf {creator: creators_address};aborts_if amount <= 0;aborts_if !exists<Collections>(creator_addr);aborts_if !table::spec_contains(collections.token_data, token_id.token_data_id);aborts_if !simple_map::spec_contains_key(token_data.default_properties.map, std::string::spec_utf8(BURNABLE_BY_OWNER));aborts_if !string::spec_internal_check_utf8(BURNABLE_BY_OWNER);
fun spec_create_token_id_raw( creator: address, collection: String, name: String, property_version: u64,): TokenId { let token_data_id = TokenDataId { creator, collection, name }; TokenId { token_data_id, property_version }}
mutate_collection_description
public fun mutate_collection_description(creator: &signer, collection_name: string::String, description: string::String)
The description of Collection is mutable.
let addr = signer::address_of(creator);let account = global<account::Account>(addr);let collection_data = table::spec_get(global<Collections>(addr).collection_data, collection_name);include AssertCollectionExistsAbortsIf { creator_address: addr, collection_name};aborts_if !collection_data.mutability_config.description;
mutate_collection_uri
public fun mutate_collection_uri(creator: &signer, collection_name: string::String, uri: string::String)
The uri of Collection is mutable.
let addr = signer::address_of(creator);let account = global<account::Account>(addr);let collection_data = table::spec_get(global<Collections>(addr).collection_data, collection_name);aborts_if len(uri.bytes) > MAX_URI_LENGTH;include AssertCollectionExistsAbortsIf { creator_address: addr, collection_name};aborts_if !collection_data.mutability_config.uri;
mutate_collection_maximum
public fun mutate_collection_maximum(creator: &signer, collection_name: string::String, maximum: u64)
Cannot change maximum from 0 and cannot change maximum to 0. The maximum should more than suply. The maxium of Collection is mutable.
let addr = signer::address_of(creator);let account = global<account::Account>(addr);let collection_data = table::spec_get(global<Collections>(addr).collection_data, collection_name);include AssertCollectionExistsAbortsIf { creator_address: addr, collection_name};aborts_if collection_data.maximum == 0 || maximum == 0;aborts_if maximum < collection_data.supply;aborts_if !collection_data.mutability_config.maximum;
mutate_tokendata_maximum
public fun mutate_tokendata_maximum(creator: &signer, token_data_id: token::TokenDataId, maximum: u64)
Cannot change maximum from 0 and cannot change maximum to 0. The maximum should more than suply. The token maximum is mutable
let addr = signer::address_of(creator);let account = global<account::Account>(addr);let all_token_data = global<Collections>(token_data_id.creator).token_data;let token_data = table::spec_get(all_token_data, token_data_id);include AssertTokendataExistsAbortsIf;aborts_if token_data.maximum == 0 || maximum == 0;aborts_if maximum < token_data.supply;aborts_if !token_data.mutability_config.maximum;
mutate_tokendata_uri
public fun mutate_tokendata_uri(creator: &signer, token_data_id: token::TokenDataId, uri: string::String)
The length of uri should less than MAX_URI_LENGTH. The creator of token_data_id should exist in Collections. The token uri is mutable
let addr = signer::address_of(creator);let account = global<account::Account>(addr);let all_token_data = global<Collections>(token_data_id.creator).token_data;let token_data = table::spec_get(all_token_data, token_data_id);include AssertTokendataExistsAbortsIf;aborts_if len(uri.bytes) > MAX_URI_LENGTH;aborts_if !token_data.mutability_config.uri;
mutate_tokendata_royalty
public fun mutate_tokendata_royalty(creator: &signer, token_data_id: token::TokenDataId, royalty: token::Royalty)
The token royalty is mutable
include AssertTokendataExistsAbortsIf;let addr = signer::address_of(creator);let account = global<account::Account>(addr);let all_token_data = global<Collections>(token_data_id.creator).token_data;let token_data = table::spec_get(all_token_data, token_data_id);aborts_if !token_data.mutability_config.royalty;
mutate_tokendata_description
public fun mutate_tokendata_description(creator: &signer, token_data_id: token::TokenDataId, description: string::String)
The token description is mutable
include AssertTokendataExistsAbortsIf;let addr = signer::address_of(creator);let account = global<account::Account>(addr);let all_token_data = global<Collections>(token_data_id.creator).token_data;let token_data = table::spec_get(all_token_data, token_data_id);aborts_if !token_data.mutability_config.description;
mutate_tokendata_property
public fun mutate_tokendata_property(creator: &signer, token_data_id: token::TokenDataId, keys: vector<string::String>, values: vector<vector<u8>>, types: vector<string::String>)
The property map is mutable
pragma aborts_if_is_partial;let all_token_data = global<Collections>(token_data_id.creator).token_data;let token_data = table::spec_get(all_token_data, token_data_id);include AssertTokendataExistsAbortsIf;aborts_if len(keys) != len(values);aborts_if len(keys) != len(types);aborts_if !token_data.mutability_config.properties;
mutate_one_token
public fun mutate_one_token(account: &signer, token_owner: address, token_id: token::TokenId, keys: vector<string::String>, values: vector<vector<u8>>, types: vector<string::String>): token::TokenId
The signer is creator. The token_data_id should exist in token_data. The property map is mutable.
pragma aborts_if_is_partial;let creator = token_id.token_data_id.creator;let addr = signer::address_of(account);let all_token_data = global<Collections>(creator).token_data;let token_data = table::spec_get(all_token_data, token_id.token_data_id);aborts_if addr != creator;aborts_if !exists<Collections>(creator);aborts_if !table::spec_contains(all_token_data, token_id.token_data_id);aborts_if !token_data.mutability_config.properties && !simple_map::spec_contains_key(token_data.default_properties.map, std::string::spec_utf8(TOKEN_PROPERTY_MUTABLE));
create_royalty
public fun create_royalty(royalty_points_numerator: u64, royalty_points_denominator: u64, payee_address: address): token::Royalty
include CreateRoyaltyAbortsIf;
The royalty_points_numerator should less than royalty_points_denominator.
schema CreateRoyaltyAbortsIf { royalty_points_numerator: u64; royalty_points_denominator: u64; payee_address: address; aborts_if royalty_points_numerator > royalty_points_denominator;}
deposit_token
public fun deposit_token(account: &signer, token: token::Token)
pragma verify = false;pragma aborts_if_is_partial;let account_addr = signer::address_of(account);include !exists<TokenStore>(account_addr) ==> InitializeTokenStore;let token_id = token.id;let token_amount = token.amount;include DirectDepositAbortsIf;
direct_deposit_with_opt_in
public fun direct_deposit_with_opt_in(account_addr: address, token: token::Token)
The token can direct_transfer.
let opt_in_transfer = global<TokenStore>(account_addr).direct_transfer;aborts_if !exists<TokenStore>(account_addr);aborts_if !opt_in_transfer;let token_id = token.id;let token_amount = token.amount;include DirectDepositAbortsIf;
direct_transfer
public fun direct_transfer(sender: &signer, receiver: &signer, token_id: token::TokenId, amount: u64)
Cannot withdraw 0 tokens. Make sure the account has sufficient tokens to withdraw.
pragma verify = false;
initialize_token_store
public fun initialize_token_store(account: &signer)
include InitializeTokenStore;
schema InitializeTokenStore { account: signer; let addr = signer::address_of(account); let account_addr = global<account::Account>(addr);}
merge
public fun merge(dst_token: &mut token::Token, source_token: token::Token)
aborts_if dst_token.id != source_token.id;aborts_if dst_token.amount + source_token.amount > MAX_U64;
split
public fun split(dst_token: &mut token::Token, amount: u64): token::Token
aborts_if dst_token.id.property_version != 0;aborts_if dst_token.amount <= amount;aborts_if amount <= 0;
transfer
public fun transfer(from: &signer, id: token::TokenId, to: address, amount: u64)
let opt_in_transfer = global<TokenStore>(to).direct_transfer;let account_addr = signer::address_of(from);aborts_if !opt_in_transfer;pragma aborts_if_is_partial;include WithdrawWithEventInternalAbortsIf;
withdraw_with_capability
public fun withdraw_with_capability(withdraw_proof: token::WithdrawCapability): token::Token
let now_seconds = global<timestamp::CurrentTimeMicroseconds>(@aptos_framework).microseconds;aborts_if !exists<timestamp::CurrentTimeMicroseconds>(@aptos_framework);aborts_if now_seconds / timestamp::MICRO_CONVERSION_FACTOR > withdraw_proof.expiration_sec;include WithdrawWithEventInternalAbortsIf{account_addr: withdraw_proof.token_owner,id: withdraw_proof.token_id,amount: withdraw_proof.amount};
partial_withdraw_with_capability
public fun partial_withdraw_with_capability(withdraw_proof: token::WithdrawCapability, withdraw_amount: u64): (token::Token, option::Option<token::WithdrawCapability>)
let now_seconds = global<timestamp::CurrentTimeMicroseconds>(@aptos_framework).microseconds;aborts_if !exists<timestamp::CurrentTimeMicroseconds>(@aptos_framework);aborts_if now_seconds / timestamp::MICRO_CONVERSION_FACTOR > withdraw_proof.expiration_sec;aborts_if withdraw_amount > withdraw_proof.amount;include WithdrawWithEventInternalAbortsIf{ account_addr: withdraw_proof.token_owner, id: withdraw_proof.token_id, amount: withdraw_amount};
withdraw_token
public fun withdraw_token(account: &signer, id: token::TokenId, amount: u64): token::Token
Cannot withdraw 0 tokens. Make sure the account has sufficient tokens to withdraw.
let account_addr = signer::address_of(account);include WithdrawWithEventInternalAbortsIf;
create_collection
public fun create_collection(creator: &signer, name: string::String, description: string::String, uri: string::String, maximum: u64, mutate_setting: vector<bool>)
The length of the name is up to MAX_COLLECTION_NAME_LENGTH; The length of the uri is up to MAX_URI_LENGTH; The collection_data should not exist before you create it.
pragma aborts_if_is_partial;let account_addr = signer::address_of(creator);aborts_if len(name.bytes) > 128;aborts_if len(uri.bytes) > 512;include CreateCollectionAbortsIf;
schema CreateCollectionAbortsIf { creator: signer; name: String; description: String; uri: String; maximum: u64; mutate_setting: vector<bool>; let addr = signer::address_of(creator); let account = global<account::Account>(addr); let collection = global<Collections>(addr); let b = !exists<Collections>(addr); let collection_data = global<Collections>(addr).collection_data; include CreateCollectionMutabilityConfigAbortsIf;}
check_collection_exists
public fun check_collection_exists(creator: address, name: string::String): bool
aborts_if !exists<Collections>(creator);
check_tokendata_exists
public fun check_tokendata_exists(creator: address, collection_name: string::String, token_name: string::String): bool
The length of collection should less than MAX_COLLECTION_NAME_LENGTH The length of name should less than MAX_NFT_NAME_LENGTH
aborts_if !exists<Collections>(creator);include CreateTokenDataIdAbortsIf { creator, collection: collection_name, name: token_name};
create_tokendata
public fun create_tokendata(account: &signer, collection: string::String, name: string::String, description: string::String, maximum: u64, uri: string::String, royalty_payee_address: address, royalty_points_denominator: u64, royalty_points_numerator: u64, token_mutate_config: token::TokenMutabilityConfig, property_keys: vector<string::String>, property_values: vector<vector<u8>>, property_types: vector<string::String>): token::TokenDataId
The length of collection should less than MAX_COLLECTION_NAME_LENGTH The length of name should less than MAX_NFT_NAME_LENGTH
pragma verify = false;pragma aborts_if_is_partial;let account_addr = signer::address_of(account);let collections = global<Collections>(account_addr);let token_data_id = spec_create_token_data_id(account_addr, collection, name);let Collection = table::spec_get(collections.collection_data, token_data_id.collection);let length = len(property_keys);aborts_if len(name.bytes) > MAX_NFT_NAME_LENGTH;aborts_if len(collection.bytes) > MAX_COLLECTION_NAME_LENGTH;aborts_if len(uri.bytes) > MAX_URI_LENGTH;aborts_if royalty_points_numerator > royalty_points_denominator;aborts_if !exists<Collections>(account_addr);include CreateTokenDataIdAbortsIf { creator: account_addr, collection, name};aborts_if !table::spec_contains(collections.collection_data, collection);aborts_if table::spec_contains(collections.token_data, token_data_id);aborts_if Collection.maximum > 0 && Collection.supply + 1 > MAX_U64;aborts_if Collection.maximum > 0 && Collection.maximum < Collection.supply + 1;include CreateRoyaltyAbortsIf { payee_address: royalty_payee_address};aborts_if length > property_map::MAX_PROPERTY_MAP_SIZE;aborts_if length != len(property_values);aborts_if length != len(property_types);
fun spec_create_token_data_id( creator: address, collection: String, name: String,): TokenDataId { TokenDataId { creator, collection, name }}
get_collection_supply
public fun get_collection_supply(creator_address: address, collection_name: string::String): option::Option<u64>
include AssertCollectionExistsAbortsIf;
get_collection_description
public fun get_collection_description(creator_address: address, collection_name: string::String): string::String
include AssertCollectionExistsAbortsIf;
get_collection_uri
public fun get_collection_uri(creator_address: address, collection_name: string::String): string::String
include AssertCollectionExistsAbortsIf;
get_collection_maximum
public fun get_collection_maximum(creator_address: address, collection_name: string::String): u64
include AssertCollectionExistsAbortsIf;
get_token_supply
public fun get_token_supply(creator_address: address, token_data_id: token::TokenDataId): option::Option<u64>
aborts_if !exists<Collections>(creator_address);let all_token_data = global<Collections>(creator_address).token_data;aborts_if !table::spec_contains(all_token_data, token_data_id);
get_tokendata_largest_property_version
public fun get_tokendata_largest_property_version(creator_address: address, token_data_id: token::TokenDataId): u64
aborts_if !exists<Collections>(creator_address);let all_token_data = global<Collections>(creator_address).token_data;aborts_if !table::spec_contains(all_token_data, token_data_id);
create_token_mutability_config
public fun create_token_mutability_config(mutate_setting: &vector<bool>): token::TokenMutabilityConfig
The length of ‘mutate_setting’ should more than five. The mutate_setting shuold have a value.
include CreateTokenMutabilityConfigAbortsIf;
schema CreateTokenMutabilityConfigAbortsIf { mutate_setting: vector<bool>; aborts_if len(mutate_setting) < 5; aborts_if !vector::spec_contains(mutate_setting, mutate_setting[TOKEN_MAX_MUTABLE_IND]); aborts_if !vector::spec_contains(mutate_setting, mutate_setting[TOKEN_URI_MUTABLE_IND]); aborts_if !vector::spec_contains(mutate_setting, mutate_setting[TOKEN_ROYALTY_MUTABLE_IND]); aborts_if !vector::spec_contains(mutate_setting, mutate_setting[TOKEN_DESCRIPTION_MUTABLE_IND]); aborts_if !vector::spec_contains(mutate_setting, mutate_setting[TOKEN_PROPERTY_MUTABLE_IND]);}
create_collection_mutability_config
public fun create_collection_mutability_config(mutate_setting: &vector<bool>): token::CollectionMutabilityConfig
include CreateCollectionMutabilityConfigAbortsIf;
schema CreateCollectionMutabilityConfigAbortsIf { mutate_setting: vector<bool>; aborts_if len(mutate_setting) < 3; aborts_if !vector::spec_contains(mutate_setting, mutate_setting[COLLECTION_DESCRIPTION_MUTABLE_IND]); aborts_if !vector::spec_contains(mutate_setting, mutate_setting[COLLECTION_URI_MUTABLE_IND]); aborts_if !vector::spec_contains(mutate_setting, mutate_setting[COLLECTION_MAX_MUTABLE_IND]);}
mint_token
public fun mint_token(account: &signer, token_data_id: token::TokenDataId, amount: u64): token::TokenId
The creator of the TokenDataId is signer. The token_data_id should exist in the creator’s collections.. The sum of supply and the amount of mint Token is less than maximum.
pragma verify = false;
schema MintTokenAbortsIf { account: signer; token_data_id: TokenDataId; amount: u64; let addr = signer::address_of(account); let creator_addr = token_data_id.creator; let all_token_data = global<Collections>(creator_addr).token_data; let token_data = table::spec_get(all_token_data, token_data_id); aborts_if token_data_id.creator != addr; aborts_if !table::spec_contains(all_token_data, token_data_id); aborts_if token_data.maximum > 0 && token_data.supply + amount > token_data.maximum; aborts_if !exists<Collections>(creator_addr); aborts_if amount <= 0; include InitializeTokenStore; let token_id = create_token_id(token_data_id, 0);}
mint_token_to
public fun mint_token_to(account: &signer, receiver: address, token_data_id: token::TokenDataId, amount: u64)
let addr = signer::address_of(account);let opt_in_transfer = global<TokenStore>(receiver).direct_transfer;let creator_addr = token_data_id.creator;let all_token_data = global<Collections>(creator_addr).token_data;let token_data = table::spec_get(all_token_data, token_data_id);aborts_if !exists<TokenStore>(receiver);aborts_if !opt_in_transfer;aborts_if token_data_id.creator != addr;aborts_if !table::spec_contains(all_token_data, token_data_id);aborts_if token_data.maximum > 0 && token_data.supply + amount > token_data.maximum;aborts_if amount <= 0;aborts_if !exists<Collections>(creator_addr);let token_id = create_token_id(token_data_id, 0);include DirectDepositAbortsIf { account_addr: receiver, token_id, token_amount: amount,};
create_token_data_id
public fun create_token_data_id(creator: address, collection: string::String, name: string::String): token::TokenDataId
The length of collection should less than MAX_COLLECTION_NAME_LENGTH The length of name should less than MAX_NFT_NAME_LENGTH
include CreateTokenDataIdAbortsIf;
schema CreateTokenDataIdAbortsIf { creator: address; collection: String; name: String; aborts_if len(collection.bytes) > MAX_COLLECTION_NAME_LENGTH; aborts_if len(name.bytes) > MAX_NFT_NAME_LENGTH;}
create_token_id_raw
public fun create_token_id_raw(creator: address, collection: string::String, name: string::String, property_version: u64): token::TokenId
The length of collection should less than MAX_COLLECTION_NAME_LENGTH The length of name should less than MAX_NFT_NAME_LENGTH
include CreateTokenDataIdAbortsIf;
fun spec_balance_of(owner: address, id: TokenId): u64 { let token_store = borrow_global<TokenStore>(owner); if (!exists<TokenStore>(owner)) { 0 } else if (table::spec_contains(token_store.tokens, id)) { table::spec_get(token_store.tokens, id).amount } else { 0 }}
get_royalty
public fun get_royalty(token_id: token::TokenId): token::Royalty
include GetTokendataRoyaltyAbortsIf { token_data_id: token_id.token_data_id};
get_property_map
public fun get_property_map(owner: address, token_id: token::TokenId): property_map::PropertyMap
let creator_addr = token_id.token_data_id.creator;let all_token_data = global<Collections>(creator_addr).token_data;aborts_if spec_balance_of(owner, token_id) <= 0;aborts_if token_id.property_version == 0 && !table::spec_contains(all_token_data, token_id.token_data_id);aborts_if token_id.property_version == 0 && !exists<Collections>(creator_addr);
get_tokendata_maximum
public fun get_tokendata_maximum(token_data_id: token::TokenDataId): u64
let creator_address = token_data_id.creator;aborts_if !exists<Collections>(creator_address);let all_token_data = global<Collections>(creator_address).token_data;aborts_if !table::spec_contains(all_token_data, token_data_id);
get_tokendata_uri
public fun get_tokendata_uri(creator: address, token_data_id: token::TokenDataId): string::String
aborts_if !exists<Collections>(creator);let all_token_data = global<Collections>(creator).token_data;aborts_if !table::spec_contains(all_token_data, token_data_id);
get_tokendata_description
public fun get_tokendata_description(token_data_id: token::TokenDataId): string::String
let creator_address = token_data_id.creator;aborts_if !exists<Collections>(creator_address);let all_token_data = global<Collections>(creator_address).token_data;aborts_if !table::spec_contains(all_token_data, token_data_id);
get_tokendata_royalty
public fun get_tokendata_royalty(token_data_id: token::TokenDataId): token::Royalty
include GetTokendataRoyaltyAbortsIf;
schema GetTokendataRoyaltyAbortsIf { token_data_id: TokenDataId; let creator_address = token_data_id.creator; let all_token_data = global<Collections>(creator_address).token_data; aborts_if !exists<Collections>(creator_address); aborts_if !table::spec_contains(all_token_data, token_data_id);}
get_tokendata_mutability_config
public fun get_tokendata_mutability_config(token_data_id: token::TokenDataId): token::TokenMutabilityConfig
let creator_addr = token_data_id.creator;let all_token_data = global<Collections>(creator_addr).token_data;aborts_if !exists<Collections>(creator_addr);aborts_if !table::spec_contains(all_token_data, token_data_id);
get_collection_mutability_config
#[view]public fun get_collection_mutability_config(creator: address, collection_name: string::String): token::CollectionMutabilityConfig
let all_collection_data = global<Collections>(creator).collection_data;aborts_if !exists<Collections>(creator);aborts_if !table::spec_contains(all_collection_data, collection_name);
withdraw_with_event_internal
fun withdraw_with_event_internal(account_addr: address, id: token::TokenId, amount: u64): token::Token
include WithdrawWithEventInternalAbortsIf;
schema WithdrawWithEventInternalAbortsIf { account_addr: address; id: TokenId; amount: u64; let tokens = global<TokenStore>(account_addr).tokens; aborts_if amount <= 0; aborts_if spec_balance_of(account_addr, id) < amount; aborts_if !exists<TokenStore>(account_addr); aborts_if !table::spec_contains(tokens, id);}
update_token_property_internal
fun update_token_property_internal(token_owner: address, token_id: token::TokenId, keys: vector<string::String>, values: vector<vector<u8>>, types: vector<string::String>)
pragma aborts_if_is_partial;let tokens = global<TokenStore>(token_owner).tokens;aborts_if !exists<TokenStore>(token_owner);aborts_if !table::spec_contains(tokens, token_id);
direct_deposit
fun direct_deposit(account_addr: address, token: token::Token)
let token_id = token.id;let token_amount = token.amount;include DirectDepositAbortsIf;
schema DirectDepositAbortsIf { account_addr: address; token_id: TokenId; token_amount: u64; let token_store = global<TokenStore>(account_addr); let recipient_token = table::spec_get(token_store.tokens, token_id); let b = table::spec_contains(token_store.tokens, token_id); aborts_if token_amount <= 0; aborts_if !exists<TokenStore>(account_addr); aborts_if b && recipient_token.id != token_id; aborts_if b && recipient_token.amount + token_amount > MAX_U64;}
assert_collection_exists
fun assert_collection_exists(creator_address: address, collection_name: string::String)
The collection_name should exist in collection_data of the creator_address’s Collections.
include AssertCollectionExistsAbortsIf;
schema AssertCollectionExistsAbortsIf { creator_address: address; collection_name: String; let all_collection_data = global<Collections>(creator_address).collection_data; aborts_if !exists<Collections>(creator_address); aborts_if !table::spec_contains(all_collection_data, collection_name);}
assert_tokendata_exists
fun assert_tokendata_exists(creator: &signer, token_data_id: token::TokenDataId)
The creator of token_data_id should be signer. The creator of token_data_id exists in Collections. The token_data_id is in the all_token_data.
include AssertTokendataExistsAbortsIf;
schema AssertTokendataExistsAbortsIf { creator: signer; token_data_id: TokenDataId; let creator_addr = token_data_id.creator; let addr = signer::address_of(creator); aborts_if addr != creator_addr; aborts_if !exists<Collections>(creator_addr); let all_token_data = global<Collections>(creator_addr).token_data; aborts_if !table::spec_contains(all_token_data, token_data_id);}
assert_non_standard_reserved_property
fun assert_non_standard_reserved_property(keys: &vector<string::String>)
pragma verify = false;
initialize_token_script
public entry fun initialize_token_script(_account: &signer)
Deprecated function
pragma verify = false;
initialize_token
public fun initialize_token(_account: &signer, _token_id: token::TokenId)
Deprecated function
pragma verify = false;