공유 객체
공유 객체는 네트워크의 누구나 접근할 수 있는 공개 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())
}