Creating and Transferring Wrapped Objects in Move
In this tutorial, we will learn how to create and transfer wrapped objects in the Move programming language. We will use a Wrapper
struct that allows any custom data with the store
ability to be freely transferable.
- Define the
Wrapper
struct: First, we will create aWrapper
struct with thekey
andstore
abilities. Thestore
ability allows the object to be transferred without a custom transfer implementation.
module examples::wrapper {
use sui::object::{Self, UID};
use sui::tx_context::TxContext;
struct Wrapper<T: store> has key, store {
id: UID,
contents: T
}
}
- Implement functions for the
Wrapper
struct: Now, we will implement functions to create, read, and destroy theWrapper
.
// View function to read contents of a `Wrapper`
public fun contents<T: store>(c: &Wrapper<T>): &T {
&c.contents
}
// Anyone can create a new object
public fun create<T: store>(contents: T, ctx: &mut TxContext): Wrapper<T> {
Wrapper {
contents,
id: object::new(ctx),
}
}
// Destroy `Wrapper` and get T
public fun destroy<T: store>(c: Wrapper<T>): T {
let Wrapper { id, contents } = c;
object::delete(id);
contents
}
}
- Use the
Wrapper
in another module: In this example, we will create aProfileInfo
struct and use theWrapper
functionality to make it transferable.
module examples::profile {
use sui::transfer;
use sui::url::{Self, Url};
use std::string::{Self, String};
use sui::tx_context::{Self, TxContext};
// using Wrapper functionality
use 0x0::wrapper;
struct ProfileInfo has store {
name: String,
url: Url
}
}
- Implement functions for the
ProfileInfo
struct: Now, we will implement functions to read thename
andurl
fields from theProfileInfo
struct.
public fun name(info: &ProfileInfo): &String {
&info.name
}
public fun url(info: &ProfileInfo): &Url {
&info.url
}
- Create a new profile and wrap it into a
Wrapper
: We will create a functioncreate_profile
to create a newProfileInfo
instance, wrap it into aWrapper
, and transfer it to the transaction sender.
public fun create_profile(
name: vector<u8>, url: vector<u8>, ctx: &mut TxContext
) {
// create a new container and wrap ProfileInfo into it
let container = wrapper::create(ProfileInfo {
name: string::utf8(name),
url: url::new_unsafe_from_bytes(url)
}, ctx);
// `Wrapper` type is freely transferable
transfer::public_transfer(container, tx_context::sender(ctx))
}
}
With this implementation, you can now create and transfer wrapped objects containing custom data in the Move programming language. Finally we get
/// A freely transfererrable Wrapper for custom data.
module examples::wrapper {
use sui::object::{Self, UID};
use sui::tx_context::TxContext;
/// An object with `store` can be transferred in any
/// module without a custom transfer implementation.
struct Wrapper<T: store> has key, store {
id: UID,
contents: T
}
/// View function to read contents of a `Container`.
public fun contents<T: store>(c: &Wrapper<T>): &T {
&c.contents
}
/// Anyone can create a new object
public fun create<T: store>(
contents: T, ctx: &mut TxContext
): Wrapper<T> {
Wrapper {
contents,
id: object::new(ctx),
}
}
/// Destroy `Wrapper` and get T.
public fun destroy<T: store> (c: Wrapper<T>): T {
let Wrapper { id, contents } = c;
object::delete(id);
contents
}
}
module examples::profile {
use sui::transfer;
use sui::url::{Self, Url};
use std::string::{Self, String};
use sui::tx_context::{Self, TxContext};
// using Wrapper functionality
use 0x0::wrapper;
/// Profile information, not an object, can be wrapped
/// into a transferable container
struct ProfileInfo has store {
name: String,
url: Url
}
/// Read `name` field from `ProfileInfo`.
public fun name(info: &ProfileInfo): &String {
&info.name
}
/// Read `url` field from `ProfileInfo`.
public fun url(info: &ProfileInfo): &Url {
&info.url
}
/// Creates new `ProfileInfo` and wraps into `Wrapper`.
/// Then transfers to sender.
public fun create_profile(
name: vector<u8>, url: vector<u8>, ctx: &mut TxContext
) {
// create a new container and wrap ProfileInfo into it
let container = wrapper::create(ProfileInfo {
name: string::utf8(name),
url: url::new_unsafe_from_bytes(url)
}, ctx);
// `Wrapper` type is freely transferable
transfer::public_transfer(container, tx_context::sender(ctx))
}
}