본문으로 건너뛰기

공유 객체

공유 객체는 네트워크의 누구나 접근할 수 있는 공개 mutable 객체이다. 여러 사용자 또는 스마트 계약이 동일한 객체와 동시에 상호작용할 수 있도록 설계되어 있다.

공유 객체 생성

sui::transfer::share_object 함수를 사용하여 shared object를 생성하면, 네트워크 상에서 공개적으로 접근할 수 있다. shared object의 확장된 기능과 접근성은 필요할 경우 접근을 보호하기 위한 추가 작업이 필요하다.

공유 객체에는 key ability가 필요하다.

public struct Donut has key { id: UID }

fun init(ctx: &mut TxContext) {
transfer::transfer(ShopOwnerCap {
id: object::new(ctx)
}, ctx.sender());

transfer::share_object(DonutShop {
id: object::new(ctx),
price: 1000,
balance: balance::zero()
})

공유 객체를 사용하는 시점

공유 객체는 marketplace, game 또는 여러 당사자가 global state에 접근하거나 이를 수정해야 하는 기타 시나리오에 적합하다.

공유 객체와 상호작용

다음 예시는 디지털 도넛을 판매하는 상점을 생성한다. 모두가 이 상점에 접근하여 도넛을 구매할 수 있어야 하므로, 예시는 sui::transfer::share_object를 사용하여 상점을 공유 객체로 생성한다.

module examples::donuts;

use sui::sui::SUI;
use sui::coin::{Self, Coin};
use sui::balance::{Self, Balance};

/// For when Coin balance is too low.
const ENotEnough: u64 = 0;

/// Capability that grants an owner the right to collect profits.
public struct ShopOwnerCap has key { id: UID }

/// A purchasable Donut. For simplicity's sake we ignore implementation.
public struct Donut has key { id: UID }

/// A shared object. `key` ability is required.
public struct DonutShop has key {
id: UID,
price: u64,
balance: Balance<SUI>
}

/// Init function is often ideal place for initializing
/// a shared object as it is called only once.
fun init(ctx: &mut TxContext) {
transfer::transfer(ShopOwnerCap {
id: object::new(ctx)
}, ctx.sender());

// Share the object to make it accessible to everyone!
transfer::share_object(DonutShop {
id: object::new(ctx),
price: 1000,
balance: balance::zero()
})
}

/// Entry function available to everyone who owns a Coin.
public fun buy_donut(
shop: &mut DonutShop, payment: &mut Coin<SUI>, ctx: &mut TxContext
) {
assert!(coin::value(payment) >= shop.price, ENotEnough);

// Take amount = `shop.price` from Coin<SUI>
let paid = payment.balance_mut.split(shop.price);

// Put the coin to the Shop's balance
shop.balance.join(paid);

transfer::transfer(Donut {
id: object::new(ctx)
}, ctx.sender())
}

/// Consume donut and get nothing...
public fun eat_donut(d: Donut) {
let Donut { id } = d;
id.delete();
}

/// Take coin from `DonutShop` and transfer it to tx sender.
/// Requires authorization with `ShopOwnerCap`.
public fun collect_profits(
_: &ShopOwnerCap, shop: &mut DonutShop, ctx: &mut TxContext
) {
let amount = shop.balance.value();
let profits = shop.balance.split(amount).into_coin(ctx);

transfer::public_transfer(profits, ctx.sender())
}