Regulated Coin

Sui provides a way to create a Coin with a global Denylist. This is useful for creating a regulated coin, where the issuer can restrict certain accounts from holding the coin. The denylist functionality is native to the network and maintains the fast path.

module examples::reg_coin {
    use std::option;
    use sui::coin;
    use sui::transfer;
    use sui::tx_context::{Self, TxContext};

    /// The type identifier of coin. The coin will have a type
    /// tag of kind: `Coin<package_object::reg_coin::REG_COIN>`
    /// Make sure that the name of the type matches the module's name.
    struct REG_COIN has drop {}

    /// Module initializer is called once on module publish. A treasury
    /// cap is sent to the publisher, who then controls minting and burning
    fun init(witness: REG_COIN, ctx: &mut TxContext) {
        // Unlike regular currency, regulated currency uses a different method.
        let (treasury, denycap, metadata) = coin::create_regulated_currency(
            witness,
            6,                           // decimals
            b"REG",                      // symbol
            b"My Coin",                  // name
            b"Do good, and you're good", // description
            option::none(),              // icon url
            ctx
        );

        // transfer the `TreasuryCap` to the sender, so they can mint and burn
        transfer::public_transfer(treasury, tx_context::sender(ctx));

        // transfer the `DenyCap` to the sender, so they can freeze and
        // unfreeze accounts from using the currency
        transfer::public_transfer(denycap, tx_context::sender(ctx));

        // metadata is typically frozen after creation
        transfer::public_freeze_object(metadata);
    }

    // === Entry Functions (can be replaced by direct calls in PTBs) ===

    use sui::deny_list::DenyList;
    use sui::coin::DenyCap;

    /// Add an account to denylist preventing them from using the currency.
    /// DenyList is a special shared object with reserved address `0x403`.
    entry fun block_account(
        deny_list: &mut DenyList,
        deny_cap: &mut DenyCap<REG_COIN>,
        account: address,
        ctx: &mut TxContext
    ) {
        coin::deny_list_add(deny_list, deny_cap, account, ctx);
    }

    /// Remove an account from denylist allowing them to use the currency.
    /// DenyList is a special shared object with reserved address `0x403`.
    entry fun unblock_account(
        deny_list: &mut DenyList,
        deny_cap: &mut DenyCap<REG_COIN>,
        account: address,
        ctx: &mut TxContext
    ) {
        coin::deny_list_remove(deny_list, deny_cap, account, ctx);
    }
}

Currently, the Denylist is only supported for the Coin type. In the future, it may be extended to some other system types.