Shared Object

Shared object is an object that is shared using a sui::transfer::share_object function and is accessible to everyone both mutably and immutably.

When sharing an object defined in this module, use transfer::share_object; for types defined in other modules, use transfer::public_share_object. Inside a transaction block, only the latter is allowed.

/// Unlike `Owned` objects, `Shared` ones can be accessed by anyone on the
/// network. Extended functionality and accessibility of this kind of objects
/// requires additional effort by securing access if needed.
module examples::donuts {
    use sui::sui::SUI;
    use sui::coin::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.
    ///
    /// To share an object `transfer::share_object` is used.
    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!(payment.value() >= 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
    ): Coin<SUI> {
        let amount = shop.balance.value();
        shop.balance.split(amount).into_coin(ctx)
    }
}