メインコンテンツまでスキップ

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.

  1. Define the Wrapper struct: First, we will create a Wrapper struct with the key and store abilities. The store 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
}
}
  1. Implement functions for the Wrapper struct: Now, we will implement functions to create, read, and destroy the Wrapper.
    // 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
}
}
  1. Use the Wrapper in another module: In this example, we will create a ProfileInfo struct and use the Wrapper 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
}
}
  1. Implement functions for the ProfileInfo struct: Now, we will implement functions to read the name and url fields from the ProfileInfo struct.
    public fun name(info: &ProfileInfo): &String {
&info.name
}

public fun url(info: &ProfileInfo): &Url {
&info.url
}
  1. Create a new profile and wrap it into a Wrapper: We will create a function create_profile to create a new ProfileInfo instance, wrap it into a Wrapper, 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))
}
}