diff --git a/crates/rooch-framework/doc/README.md b/crates/rooch-framework/doc/README.md
index e665567beb..4ab41a272f 100644
--- a/crates/rooch-framework/doc/README.md
+++ b/crates/rooch-framework/doc/README.md
@@ -26,6 +26,7 @@ This is the reference documentation of the Rooch Framework.
- [`0x3::coin_store`](coin_store.md#0x3_coin_store)
- [`0x3::core_addresses`](core_addresses.md#0x3_core_addresses)
- [`0x3::decoding`](decoding.md#0x3_decoding)
+- [`0x3::display`](display.md#0x3_display)
- [`0x3::ecdsa_k1`](ecdsa_k1.md#0x3_ecdsa_k1)
- [`0x3::ecdsa_k1_recoverable`](ecdsa_k1_recoverable.md#0x3_ecdsa_k1_recoverable)
- [`0x3::ed25519`](ed25519.md#0x3_ed25519)
diff --git a/crates/rooch-framework/doc/display.md b/crates/rooch-framework/doc/display.md
new file mode 100644
index 0000000000..d9e563b594
--- /dev/null
+++ b/crates/rooch-framework/doc/display.md
@@ -0,0 +1,253 @@
+
+
+
+# Module `0x3::display`
+
+
+
+- [Resource `Display`](#0x3_display_Display)
+- [Function `new`](#0x3_display_new)
+- [Function `set`](#0x3_display_set)
+- [Function `borrow`](#0x3_display_borrow)
+- [Function `borrow_mut`](#0x3_display_borrow_mut)
+- [Function `remove`](#0x3_display_remove)
+- [Function `keys`](#0x3_display_keys)
+- [Function `values`](#0x3_display_values)
+- [Function `contains_key`](#0x3_display_contains_key)
+
+
+
use 0x1::string;
+use 0x2::context;
+use 0x2::object_ref;
+use 0x2::simple_map;
+
+
+
+
+
+
+## Resource `Display`
+
+
+
+struct Display<T> has copy, drop, store, key
+
+
+
+
+
+Fields
+
+
+
+-
+
sample_map: simple_map::SimpleMap<string::String, string::String>
+
+-
+
+
+
+
+
+
+
+
+
+## Function `new`
+
+
+
+public fun new<T>(ctx: &mut context::Context): object_ref::ObjectRef<display::Display<T>>
+
+
+
+
+
+Implementation
+
+
+public fun new<T>(ctx: &mut Context): ObjectRef<Display<T>> {
+ context::new_singleton_object(ctx, Display<T> {
+ sample_map: simple_map::create()
+ })
+}
+
+
+
+
+
+
+
+
+## Function `set`
+
+
+
+public fun set<T>(self: &mut object_ref::ObjectRef<display::Display<T>>, key: string::String, value: string::String)
+
+
+
+
+
+Implementation
+
+
+public fun set<T>(self: &mut ObjectRef<Display<T>>, key: String, value: String) {
+ let display_ref = object_ref::borrow_mut(self);
+ simple_map::add(&mut display_ref.sample_map, key, value);
+}
+
+
+
+
+
+
+
+
+## Function `borrow`
+
+
+
+public fun borrow<T>(self: &object_ref::ObjectRef<display::Display<T>>, key: &string::String): &string::String
+
+
+
+
+
+Implementation
+
+
+public fun borrow<T>(self: & ObjectRef<Display<T>> , key: &String): &String {
+ let display_ref = object_ref::borrow(self);
+ simple_map::borrow(&display_ref.sample_map, key)
+}
+
+
+
+
+
+
+
+
+## Function `borrow_mut`
+
+
+
+public fun borrow_mut<T>(self: &mut object_ref::ObjectRef<display::Display<T>>, key: &string::String): &mut string::String
+
+
+
+
+
+Implementation
+
+
+public fun borrow_mut<T>(self: &mut ObjectRef<Display<T>>, key: &String): &mut String {
+ let display_ref = object_ref::borrow_mut(self);
+ simple_map::borrow_mut(&mut display_ref.sample_map, key)
+}
+
+
+
+
+
+
+
+
+## Function `remove`
+
+
+
+public fun remove<T>(self: &mut object_ref::ObjectRef<display::Display<T>>, key: &string::String)
+
+
+
+
+
+Implementation
+
+
+public fun remove<T>(self: &mut ObjectRef<Display<T>>, key: &String) {
+ let display_ref = object_ref::borrow_mut(self);
+ simple_map::remove(&mut display_ref.sample_map, key);
+}
+
+
+
+
+
+
+
+
+## Function `keys`
+
+
+
+public fun keys<T>(self: &object_ref::ObjectRef<display::Display<T>>): vector<string::String>
+
+
+
+
+
+Implementation
+
+
+public fun keys<T>(self: & ObjectRef<Display<T>>): vector<String> {
+ let display_ref = object_ref::borrow(self);
+ simple_map::keys(& display_ref.sample_map)
+}
+
+
+
+
+
+
+
+
+## Function `values`
+
+
+
+public fun values<T>(self: &object_ref::ObjectRef<display::Display<T>>): vector<string::String>
+
+
+
+
+
+Implementation
+
+
+public fun values<T>(self: & ObjectRef<Display<T>>): vector<String> {
+ let display_ref = object_ref::borrow(self);
+ simple_map::values(& display_ref.sample_map)
+}
+
+
+
+
+
+
+
+
+## Function `contains_key`
+
+
+
+public fun contains_key<T>(self: &object_ref::ObjectRef<display::Display<T>>, key: &string::String): bool
+
+
+
+
+
+Implementation
+
+
+public fun contains_key<T>(self: & ObjectRef<Display<T>>, key: &String): bool {
+ let display_ref = object_ref::borrow(self);
+ simple_map::contains_key(& display_ref.sample_map, key)
+}
+
+
+
+
+
diff --git a/crates/rooch-framework/sources/display.move b/crates/rooch-framework/sources/display.move
new file mode 100644
index 0000000000..3fb5223385
--- /dev/null
+++ b/crates/rooch-framework/sources/display.move
@@ -0,0 +1,54 @@
+module rooch_framework::display{
+ use std::string::String;
+ use moveos_std::object_ref;
+ use moveos_std::context::Context;
+ use moveos_std::context;
+ use moveos_std::object_ref::ObjectRef;
+ use moveos_std::simple_map;
+
+ struct Display has key, store,drop,copy {
+ sample_map: simple_map::SimpleMap
+ }
+
+ public fun new(ctx: &mut Context): ObjectRef> {
+ context::new_singleton_object(ctx, Display {
+ sample_map: simple_map::create()
+ })
+ }
+
+ public fun set(self: &mut ObjectRef>, key: String, value: String) {
+ let display_ref = object_ref::borrow_mut(self);
+ simple_map::add(&mut display_ref.sample_map, key, value);
+ }
+
+ public fun borrow(self: & ObjectRef> , key: &String): &String {
+ let display_ref = object_ref::borrow(self);
+ simple_map::borrow(&display_ref.sample_map, key)
+ }
+
+ public fun borrow_mut(self: &mut ObjectRef>, key: &String): &mut String {
+ let display_ref = object_ref::borrow_mut(self);
+ simple_map::borrow_mut(&mut display_ref.sample_map, key)
+ }
+
+ public fun remove(self: &mut ObjectRef>, key: &String) {
+ let display_ref = object_ref::borrow_mut(self);
+ simple_map::remove(&mut display_ref.sample_map, key);
+ }
+
+ public fun keys(self: & ObjectRef>): vector {
+ let display_ref = object_ref::borrow(self);
+ simple_map::keys(& display_ref.sample_map)
+ }
+
+ public fun values(self: & ObjectRef>): vector {
+ let display_ref = object_ref::borrow(self);
+ simple_map::values(& display_ref.sample_map)
+ }
+
+ public fun contains_key(self: & ObjectRef>, key: &String): bool {
+ let display_ref = object_ref::borrow(self);
+ simple_map::contains_key(& display_ref.sample_map, key)
+ }
+
+}
\ No newline at end of file
diff --git a/examples/nft/Move.toml b/examples/nft/Move.toml
new file mode 100644
index 0000000000..2142484e39
--- /dev/null
+++ b/examples/nft/Move.toml
@@ -0,0 +1,14 @@
+[package]
+name = "nft"
+version = "0.0.1"
+
+[dependencies]
+MoveStdlib = { local = "../../moveos/moveos-stdlib/move-stdlib" }
+MoveosStdlib = { local = "../../moveos/moveos-stdlib/moveos-stdlib" }
+RoochFramework = { local = "../../crates/rooch-framework" }
+
+[addresses]
+nft = "_"
+
+[dev-addresses]
+nft = "0x42"
\ No newline at end of file
diff --git a/examples/nft/README.md b/examples/nft/README.md
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/examples/nft/sources/collection.move b/examples/nft/sources/collection.move
new file mode 100644
index 0000000000..2d6844deeb
--- /dev/null
+++ b/examples/nft/sources/collection.move
@@ -0,0 +1,240 @@
+// Copyright (c) RoochNetwork
+// SPDX-License-Identifier: Apache-2.0
+
+module nft::collection{
+ use std::option;
+ use std::option::Option;
+ use std::string::String;
+ use rooch_framework::display::{Self, Display};
+ use moveos_std::object::{Self, ObjectID};
+ use moveos_std::event;
+ use moveos_std::context::{Self, Context};
+ use moveos_std::object_ref::{Self, ObjectRef};
+ use moveos_std::type_table;
+
+ friend nft::nft;
+
+ const ErrorMutatorNotExist: u64 = 1;
+ const ErrorCollectionNotExist: u64 = 2;
+ const ErrorCollectionMaximumSupply: u64 = 3;
+
+ struct Collection has key{
+ name: String,
+ uri: String,
+ creator: address,
+ supply: Supply,
+ extend: type_table::TypeTable
+ }
+
+ struct Supply has store{
+ current: u64,
+ maximum: Option,
+ }
+
+ struct MutatorRef has key,store{
+ collection: ObjectID,
+ }
+
+ struct CreateCollectionEvent{
+ objectID: ObjectID,
+ name: String,
+ uri: String,
+ creator: address,
+ maximum: Option,
+ description: String,
+ }
+
+ public(friend) fun create_collection(
+ name: String,
+ uri: String,
+ creator: address,
+ description: String,
+ max_supply: Option,
+ ctx: &mut Context
+ ):ObjectRef> {
+
+ let collection = Collection {
+ name,
+ uri,
+ creator,
+ supply: Supply {
+ current: 0,
+ maximum: max_supply,
+ },
+ extend: type_table::new(ctx)
+ };
+
+ let object_ref = context::new_object_with_owner(
+ ctx,
+ creator,
+ collection
+ );
+
+ event::emit(
+ ctx,
+ CreateCollectionEvent {
+ objectID: object_ref::id(&object_ref),
+ name,
+ uri,
+ creator,
+ maximum: max_supply,
+ description,
+ }
+ );
+ object_ref
+ }
+
+ public fun generate_mutator_ref(collection: &ObjectRef>):MutatorRef{
+ MutatorRef {
+ collection: object_ref::id(collection),
+ }
+ }
+
+ public(friend) fun new_display(ctx: &mut Context):ObjectRef>>{
+ display::new>(ctx)
+ }
+
+ public fun destroy_mutator_ref(mutator_ref :MutatorRef):ObjectID{
+ let MutatorRef {
+ collection,
+ } = mutator_ref;
+ collection
+ }
+
+ public fun get_collection_id(mutator: &MutatorRef): ObjectID{
+ mutator.collection
+ }
+
+
+ public(friend) fun increment_supply(mutator: &MutatorRef, ctx: &mut Context): Option{
+ assert_collection_exist_of_id(mutator.collection, ctx);
+ let collection_object_mut_ref = context::borrow_object_mut>(ctx, mutator.collection);
+ let collection_mut_ref = object::borrow_mut(collection_object_mut_ref);
+ collection_mut_ref.supply.current = collection_mut_ref.supply.current + 1;
+ if(option::is_some(&collection_mut_ref.supply.maximum)){
+ assert!(collection_mut_ref.supply.current <= *option::borrow(&collection_mut_ref.supply.maximum), ErrorCollectionMaximumSupply);
+ option::some(collection_mut_ref.supply.current)
+ }else{
+ option::none()
+ }
+ }
+
+ public (friend) fun decrement_supply(mutator: &MutatorRef, ctx: &mut Context): Option{
+ assert_collection_exist_of_id(mutator.collection, ctx);
+ let collection_object_mut_ref = context::borrow_object_mut>(ctx, mutator.collection);
+ let collection_mut_ref = object::borrow_mut(collection_object_mut_ref);
+ collection_mut_ref.supply.current = collection_mut_ref.supply.current - 1;
+ if(option::is_some(&collection_mut_ref.supply.maximum)){
+ option::some(collection_mut_ref.supply.current)
+ }else{
+ option::none()
+ }
+ }
+
+ // assert
+ public fun assert_collection_exist_of_ref(collectionRef: &ObjectRef>){
+ assert!( object_ref::exist_object(collectionRef), ErrorCollectionNotExist);
+ }
+
+ public fun assert_collection_exist_of_id(collectionID: ObjectID, ctx: & Context){
+ assert!( context::exist_object(ctx, collectionID), ErrorCollectionNotExist);
+ context::borrow_object>(ctx,collectionID);
+ }
+
+ #[private_generics(V)]
+ public fun add_extend(mutator: &MutatorRef, val: V, ctx: &mut Context){
+ add_extend_internal(mutator, val, ctx);
+ }
+
+ #[private_generics(V)]
+ public fun borrow_extend(mutator: &MutatorRef, ctx: &mut Context):&V{
+ borrow_extend_internal(mutator, ctx)
+ }
+
+ #[private_generics(V)]
+ public fun borrow_mut_extend(mutator: &MutatorRef, ctx: &mut Context):&mut V{
+ borrow_mut_extend_internal(mutator, ctx)
+ }
+
+ #[private_generics(V)]
+ public fun remove_extend(mutator: &MutatorRef, ctx: &mut Context):V{
+ remove_extend_internal(mutator, ctx)
+ }
+
+ public fun contains_extend(mutator: &MutatorRef, ctx: &mut Context): bool{
+ contains_extend_internal(mutator, ctx)
+ }
+
+
+ fun add_extend_internal(mutator: &MutatorRef,val: V,ctx: &mut Context){
+ assert_collection_exist_of_id(mutator.collection, ctx);
+ let collection_object_mut_ref = context::borrow_object_mut>(ctx, mutator.collection);
+ let collection_mut_ref = object::borrow_mut(collection_object_mut_ref);
+ type_table::add( &mut collection_mut_ref.extend, val);
+ }
+
+ fun borrow_extend_internal(mutator: &MutatorRef, ctx: &mut Context):&V{
+ assert_collection_exist_of_id(mutator.collection, ctx);
+ let collection_object_ref = context::borrow_object>(ctx, mutator.collection);
+ let collection_ref = object::borrow(collection_object_ref);
+ type_table::borrow(&collection_ref.extend)
+ }
+
+ fun borrow_mut_extend_internal(mutator: &MutatorRef, ctx: &mut Context):&mut V{
+ assert_collection_exist_of_id(mutator.collection, ctx);
+ let collection_object_mut_ref = context::borrow_object_mut>(ctx, mutator.collection);
+ let collection_mut_ref = object::borrow_mut(collection_object_mut_ref);
+ type_table::borrow_mut(&mut collection_mut_ref.extend)
+ }
+
+ fun remove_extend_internal(mutator: &MutatorRef, ctx: &mut Context):V{
+ assert_collection_exist_of_id(mutator.collection, ctx);
+ let collection_object_mut_ref = context::borrow_object_mut>(ctx, mutator.collection);
+ let collection_mut_ref = object::borrow_mut(collection_object_mut_ref);
+ type_table::remove(&mut collection_mut_ref.extend)
+ }
+
+ fun contains_extend_internal(mutator: &MutatorRef, ctx: &mut Context): bool{
+ assert_collection_exist_of_id(mutator.collection, ctx);
+ let collection_object_ref = context::borrow_object>(ctx, mutator.collection);
+ let collection_ref = object::borrow(collection_object_ref);
+ type_table::contains(&collection_ref.extend)
+ }
+
+ // view
+ public fun get_collection_name(collectionID: ObjectID, ctx: &mut Context): String{
+ assert_collection_exist_of_id(collectionID, ctx);
+ let collection_object_ref = context::borrow_object>(ctx, collectionID);
+ let collection_ref = object::borrow(collection_object_ref);
+ collection_ref.name
+ }
+
+ public fun get_collection_uri(collectionID: ObjectID, ctx: &mut Context): String{
+ assert_collection_exist_of_id(collectionID, ctx);
+ let collection_object_ref = context::borrow_object>(ctx, collectionID);
+ let collection_ref = object::borrow(collection_object_ref);
+ collection_ref.uri
+ }
+
+ public fun get_collection_creator(collectionID: ObjectID, ctx: &mut Context): address{
+ assert_collection_exist_of_id(collectionID, ctx);
+ let collection_object_ref = context::borrow_object>(ctx, collectionID);
+ let collection_ref = object::borrow(collection_object_ref);
+ collection_ref.creator
+ }
+
+ public fun get_collection_current_supply(collectionID: ObjectID, ctx: &mut Context): u64{
+ assert_collection_exist_of_id(collectionID, ctx);
+ let collection_object_ref = context::borrow_object>(ctx, collectionID);
+ let collection_ref = object::borrow(collection_object_ref);
+ collection_ref.supply.current
+ }
+
+ public fun get_collection_maximum_supply(collectionID: ObjectID, ctx: &mut Context): Option{
+ assert_collection_exist_of_id(collectionID, ctx);
+ let collection_object_ref = context::borrow_object>(ctx, collectionID);
+ let collection_ref = object::borrow(collection_object_ref);
+ collection_ref.supply.maximum
+ }
+
+}
diff --git a/examples/nft/sources/nft.move b/examples/nft/sources/nft.move
new file mode 100644
index 0000000000..110c11bb87
--- /dev/null
+++ b/examples/nft/sources/nft.move
@@ -0,0 +1,289 @@
+// Copyright (c) RoochNetwork
+// SPDX-License-Identifier: Apache-2.0
+
+module nft::nft {
+ use std::option::Option;
+ use std::string::String;
+ use nft::collection::{Self, Collection};
+ use rooch_framework::display::{Self, Display};
+ use moveos_std::object_ref::{Self, ObjectRef};
+ use moveos_std::context::{Self, Context};
+ use moveos_std::type_table;
+ use moveos_std::object::{Self, ObjectID};
+ use moveos_std::type_table::TypeTable;
+ #[test_only]
+ use std::option;
+ #[test_only]
+ use std::string;
+ #[test_only]
+ use rooch_framework::account;
+
+ const ErrorNftNotExist: u64 = 1;
+ const ErrorMutatorNotExist: u64 = 2;
+ const ErrorBurnerNotExist: u64 = 3;
+
+ struct NFT has key,store {
+ name: String,
+ uri: String,
+ collection: ObjectID,
+ creator: address,
+ extend: TypeTable
+ }
+
+ struct MutatorRef has key,store {
+ nft: ObjectID,
+ }
+
+ struct BurnerRef has key,store {
+ nft: ObjectID,
+ }
+
+ #[private_generics(T)]
+ public fun create_collection(
+ name: String,
+ uri: String,
+ creator: address,
+ description: String,
+ supply: Option,
+ ctx: &mut Context
+ ):(ObjectRef>,ObjectRef>>,ObjectRef>>) {
+ let collection_object_ref = collection::create_collection(
+ name,
+ uri,
+ creator,
+ description,
+ supply,
+ ctx
+ );
+ let collection_display_object_ref = collection::new_display(ctx);
+ let nft_display_object_ref = display::new>(ctx);
+
+ (collection_object_ref, collection_display_object_ref, nft_display_object_ref)
+ }
+
+ #[private_generics(T)]
+ public fun mint(
+ name: String,
+ uri: String,
+ mutator_ref: &collection::MutatorRef,
+ creator: address,
+ ctx: &mut Context
+ ): ObjectRef> {
+ let nft = NFT {
+ name,
+ uri,
+ collection: collection::get_collection_id(mutator_ref),
+ creator,
+ extend: type_table::new(ctx)
+ };
+
+ collection::increment_supply(mutator_ref, ctx);
+
+ let object_ref = context::new_object_with_owner(
+ ctx,
+ creator,
+ nft
+ );
+
+ object_ref
+ }
+
+ public fun burn (
+ burn_ref: &BurnerRef,
+ mutator_ref: & collection::MutatorRef,
+ ctx: &mut Context
+ ) {
+ assert_nft_exist_of_id(burn_ref.nft, ctx);
+ collection::decrement_supply(mutator_ref, ctx);
+ let (
+ _,
+ _,
+ NFT {
+ name:_,
+ uri:_,
+ collection:_,
+ creator:_,
+ extend
+ }
+ ) = context::remove_object>(ctx, burn_ref.nft);
+ if(type_table::contains>( &extend )){
+ type_table::remove>( &mut extend);
+ };
+ type_table::destroy_empty(extend)
+ }
+
+ public fun generate_mutator_ref(nft_object_ref: &ObjectRef>):MutatorRef{
+ MutatorRef {
+ nft: object_ref::id(nft_object_ref),
+ }
+ }
+
+ public fun destroy_mutator_ref(mutator_ref :MutatorRef):ObjectID{
+ let MutatorRef {
+ nft
+ } = mutator_ref ;
+ nft
+ }
+
+ public fun generate_burner_ref(nft_object_ref: &ObjectRef>):BurnerRef{
+ BurnerRef {
+ nft: object_ref::id(nft_object_ref),
+ }
+ }
+
+ public fun destroy_burner_ref(burner_ref :BurnerRef):ObjectID{
+ let BurnerRef {
+ nft
+ } = burner_ref;
+ nft
+ }
+
+ // assert
+ public fun assert_nft_exist_of_id(objectId: ObjectID, ctx: &Context) {
+ assert!(context::exist_object(ctx, objectId), ErrorNftNotExist);
+ context::borrow_object>(ctx, objectId);
+ }
+
+ public fun assert_nft_exist_of_ref(nft_object_ref: &ObjectRef>) {
+ assert!(object_ref::exist_object(nft_object_ref), ErrorNftNotExist);
+ }
+
+ #[private_generics(V)]
+ public fun add_extend(mutator: &MutatorRef, val: V, ctx: &mut Context){
+ add_extend_internal(mutator, val, ctx);
+ }
+
+ public fun borrow_extend(mutator: &MutatorRef, ctx: &mut Context):&V{
+ borrow_extend_internal(mutator, ctx)
+ }
+
+ #[private_generics(V)]
+ public fun borrow_mut_extend(mutator: &MutatorRef, ctx: &mut Context):&mut V{
+ borrow_mut_extend_internal(mutator, ctx)
+ }
+
+ #[private_generics(V)]
+ public fun remove_extend(mutator: &MutatorRef, ctx: &mut Context):V{
+ remove_extend_internal(mutator, ctx)
+ }
+
+ public fun contains_extend(mutator: &MutatorRef, ctx: &mut Context): bool{
+ contains_extend_internal(mutator, ctx)
+ }
+
+ fun add_extend_internal(mutator: &MutatorRef,val: V,ctx: &mut Context) {
+ let nft_object_mut_ref = context::borrow_object_mut>(ctx, mutator.nft);
+ let nft_mut_ref = object::borrow_mut(nft_object_mut_ref);
+ type_table::add( &mut nft_mut_ref.extend, val);
+ }
+
+ fun borrow_extend_internal(mutator: &MutatorRef,ctx: &Context): &V {
+ let nft_object_ref = context::borrow_object>(ctx, mutator.nft);
+ let nft_mut_ref = object::borrow(nft_object_ref);
+ type_table::borrow(&nft_mut_ref.extend)
+ }
+
+ fun borrow_mut_extend_internal(mutator: &MutatorRef,ctx: &mut Context): &mut V {
+ let nft_object_mut_ref = context::borrow_object_mut>(ctx, mutator.nft);
+ let nft_mut_ref = object::borrow_mut(nft_object_mut_ref);
+ type_table::borrow_mut(&mut nft_mut_ref.extend)
+ }
+
+ fun remove_extend_internal(mutator: &MutatorRef,ctx: &mut Context):V {
+ let nft_object_mut_ref = context::borrow_object_mut>(ctx, mutator.nft);
+ let nft_mut_ref = object::borrow_mut(nft_object_mut_ref);
+ type_table::remove(&mut nft_mut_ref.extend)
+ }
+
+ fun contains_extend_internal(mutator: &MutatorRef,ctx: &Context): bool {
+ let nft_object_ref = context::borrow_object>(ctx, mutator.nft);
+ let nft_mut_ref = object::borrow(nft_object_ref);
+ type_table::contains(&nft_mut_ref.extend)
+ }
+
+ // view
+
+ public fun get_name(objectId: ObjectID, ctx: &Context): String {
+ assert_nft_exist_of_id(objectId, ctx);
+ let nft_object_ref = context::borrow_object>(ctx, objectId);
+ let nft = object::borrow(nft_object_ref);
+ nft.name
+ }
+
+ public fun get_uri(objectId: ObjectID, ctx: &Context): String {
+ assert_nft_exist_of_id(objectId, ctx);
+ let nft_object_ref = context::borrow_object>(ctx, objectId);
+ let nft = object::borrow(nft_object_ref);
+ nft.uri
+ }
+
+ public fun get_collection(objectId: ObjectID, ctx: &Context): ObjectID {
+ assert_nft_exist_of_id(objectId, ctx);
+ let nft_object_ref = context::borrow_object>(ctx, objectId);
+ let nft = object::borrow(nft_object_ref);
+ nft.collection
+ }
+
+ public fun get_creator(objectId: ObjectID, ctx: &Context): address {
+ assert_nft_exist_of_id(objectId, ctx);
+ let nft_object_ref = context::borrow_object>(ctx, objectId);
+ let nft = object::borrow(nft_object_ref);
+ nft.creator
+ }
+
+ #[test_only]
+ struct Test has key {}
+
+ #[test(sender = @nft)]
+ public fun test_create_nft (sender: address){
+ let storage_context = context::new_test_context(sender);
+ let ctx = &mut storage_context;
+ account::create_account_for_test(ctx, sender);
+
+ let (
+ collection_object_ref,
+ collection_display_object_ref,
+ nft_display_object_ref
+ ) = create_collection(
+ string::utf8(b"name"),
+ string::utf8(b"uri"),
+ sender,
+ string::utf8(b"description"),
+ option::none(),
+ ctx
+ );
+
+ let collection_mutator_ref = collection::generate_mutator_ref(&collection_object_ref);
+
+ display::set(&mut collection_display_object_ref, string::utf8(b"name"), string::utf8(b"{ name }"));
+ display::set(&mut collection_display_object_ref, string::utf8(b"uri"), string::utf8(b"{ uri }"));
+ display::set(&mut collection_display_object_ref, string::utf8(b"description"), string::utf8(b"{ description }"));
+ display::set(&mut collection_display_object_ref, string::utf8(b"creator"), string::utf8(b"{ creator }"));
+ display::set(&mut collection_display_object_ref, string::utf8(b"supply"), string::utf8(b"{ supply }"));
+
+ display::set(&mut nft_display_object_ref, string::utf8(b"name"), string::utf8(b"{ name }"));
+ display::set(&mut nft_display_object_ref, string::utf8(b"uri"), string::utf8(b"{ uri }"));
+
+ let nft_object_ref = mint(
+ string::utf8(b"name"),
+ string::utf8(b"uri"),
+ &collection_mutator_ref,
+ sender,
+ ctx
+ );
+
+ let nft_mutaor_ref = generate_mutator_ref(&nft_object_ref);
+
+ let burner_ref = generate_burner_ref(&nft_object_ref);
+
+ burn(&burner_ref, &collection_mutator_ref, ctx);
+
+ collection::destroy_mutator_ref(collection_mutator_ref);
+
+ destroy_mutator_ref(nft_mutaor_ref);
+ destroy_burner_ref(burner_ref);
+
+ context::drop_test_context(storage_context);
+ }
+
+}
\ No newline at end of file
diff --git a/moveos/moveos-stdlib/moveos-stdlib/doc/context.md b/moveos/moveos-stdlib/moveos-stdlib/doc/context.md
index 1ff0bc4fe5..238f5472f0 100644
--- a/moveos/moveos-stdlib/moveos-stdlib/doc/context.md
+++ b/moveos/moveos-stdlib/moveos-stdlib/doc/context.md
@@ -28,6 +28,7 @@ and let developers customize the storage
- [Function `new_object`](#0x2_context_new_object)
- [Function `new_object_with_owner`](#0x2_context_new_object_with_owner)
- [Function `new_object_with_id`](#0x2_context_new_object_with_id)
+- [Function `new_singleton_object`](#0x2_context_new_singleton_object)
use 0x1::option;
@@ -37,6 +38,7 @@ and let developers customize the storage
use 0x2::tx_context;
use 0x2::tx_meta;
use 0x2::tx_result;
+use 0x2::type_info;
@@ -557,4 +559,29 @@ Add the Object to the global object storage and return the ObjectRef
+
+
+
+
+## Function `new_singleton_object`
+
+
+
+public fun new_singleton_object<T: key>(self: &mut context::Context, value: T): object_ref::ObjectRef<T>
+
+
+
+
+
+Implementation
+
+
+public fun new_singleton_object<T: key>(self: &mut Context, value: T): ObjectRef<T> {
+ let object_id = object::singleton_object_id<T>();
+ new_object_with_id(self, object_id, type_info::account_address(&type_info::type_of<T>()), value)
+}
+
+
+
+
diff --git a/moveos/moveos-stdlib/moveos-stdlib/doc/object.md b/moveos/moveos-stdlib/moveos-stdlib/doc/object.md
index bdb46c7c27..0908662a47 100644
--- a/moveos/moveos-stdlib/moveos-stdlib/doc/object.md
+++ b/moveos/moveos-stdlib/moveos-stdlib/doc/object.md
@@ -13,6 +13,7 @@ The differents with the Object in [Sui](https://github.com/MystenLabs/sui/blob/5
- [Struct `Object`](#0x2_object_Object)
- [Struct `ObjectID`](#0x2_object_ObjectID)
- [Function `address_to_object_id`](#0x2_object_address_to_object_id)
+- [Function `singleton_object_id`](#0x2_object_singleton_object_id)
- [Function `new`](#0x2_object_new)
- [Function `borrow`](#0x2_object_borrow)
- [Function `internal_borrow`](#0x2_object_internal_borrow)
@@ -25,7 +26,11 @@ The differents with the Object in [Sui](https://github.com/MystenLabs/sui/blob/5
- [Function `unpack_internal`](#0x2_object_unpack_internal)
-
+use 0x1::hash;
+use 0x2::address;
+use 0x2::bcs;
+use 0x2::type_info;
+
@@ -121,6 +126,38 @@ Generate a new ObjectID from an address
+
+
+
+
+## Function `singleton_object_id`
+
+
+
+public(friend) fun singleton_object_id<T>(): object::ObjectID
+
+
+
+
+
+Implementation
+
+
+public(friend) fun singleton_object_id<T>(): ObjectID {
+ address_to_object_id(
+ address::from_bytes(
+ hash::sha3_256(
+ bcs::to_bytes(
+ &type_info::type_of<T>()
+ )
+ )
+ )
+ )
+}
+
+
+
+
diff --git a/moveos/moveos-stdlib/moveos-stdlib/sources/context.move b/moveos/moveos-stdlib/moveos-stdlib/sources/context.move
index 44d1d97e1a..1cfde4e72a 100644
--- a/moveos/moveos-stdlib/moveos-stdlib/sources/context.move
+++ b/moveos/moveos-stdlib/moveos-stdlib/sources/context.move
@@ -7,6 +7,7 @@
module moveos_std::context {
use std::option::Option;
+ use moveos_std::type_info;
use moveos_std::storage_context::{Self, StorageContext};
use moveos_std::tx_context::{Self, TxContext};
use moveos_std::object::{Self, Object, ObjectID};
@@ -142,6 +143,12 @@ module moveos_std::context {
obj_ref
}
+ #[private_generics(T)]
+ public fun new_singleton_object(self: &mut Context, value: T): ObjectRef {
+ let object_id = object::singleton_object_id();
+ new_object_with_id(self, object_id, type_info::account_address(&type_info::type_of()), value)
+ }
+
#[test_only]
/// Create a Context for unit test
public fun new_test_context(sender: address): Context {
diff --git a/moveos/moveos-stdlib/moveos-stdlib/sources/object.move b/moveos/moveos-stdlib/moveos-stdlib/sources/object.move
index 3a94b45469..91671cf4cd 100644
--- a/moveos/moveos-stdlib/moveos-stdlib/sources/object.move
+++ b/moveos/moveos-stdlib/moveos-stdlib/sources/object.move
@@ -7,8 +7,11 @@
/// 1. The Object is a struct in Move
/// 2. The Object is a use case of the Hot Potato pattern in Move. Objects do not have any ability, so they cannot be drop, copy, or store, and can only be handled by StorageContext API after creation.
module moveos_std::object {
-
-
+
+ use std::hash;
+ use moveos_std::type_info;
+ use moveos_std::bcs;
+ use moveos_std::address;
friend moveos_std::context;
friend moveos_std::account_storage;
friend moveos_std::storage_context;
@@ -39,6 +42,18 @@ module moveos_std::object {
ObjectID { id: address }
}
+ public(friend) fun singleton_object_id(): ObjectID {
+ address_to_object_id(
+ address::from_bytes(
+ hash::sha3_256(
+ bcs::to_bytes(
+ &type_info::type_of()
+ )
+ )
+ )
+ )
+ }
+
/// Create a new object, the object is owned by `owner`
public(friend) fun new(id: ObjectID, owner: address, value: T): Object {
Object{id, value, owner}