Saltearse al contenido

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;