본문으로 건너뛰기

통화와 토큰 만들기

Coin Registry 시스템은 sui::coin_registry 모듈을 통해 통화 관리에 대한 중앙화된 접근 방식을 제공한다. 레지스트리는 address 0xc에 위치한 shared object이며, 등록된 모든 코인 타입의 메타데이터, 공급 정보, 규제 상태를 저장한다.

sui::token 모듈은 네트워크에서 토큰 생성을 처리한다. 이러한 기능에 대한 자세한 내용은 Closed-Loop TokenCurrency standards 문서를 참고한다.

Currency creation process

레지스트리 시스템은 두 가지 통화 생성 방법을 지원한다:

  1. Standard creation: 패키지의 init 함수 밖에서 코인을 생성할 때 new_currency<T>()를 호출한다.
  2. OTW creation: 고유성 증명을 위해 One-Time Witness와 함께 new_currency_with_otw<T>()를 사용한다.
주의

적절한 생성과 RPC 지원을 위해서는 통화를 레지스트리로 승격하는 두 번째 transaction이 필수이다.

두 방법 모두 finalize 전에 구성을 허용하는 CurrencyInitializer<T>를 반환한다:

Click to open

Regular currency creation

/// Implements a coin with a deflationary supply. Upon initialization, mint the
/// total supply and give up `TreasuryCap` to make the supply deflationary (prevents
/// minting but allows burning).
///
/// Keep the ability to update Currency metadata, such as name, symbol,
/// description, and icon URL.
module examples::currency;

use sui::coin::Coin;
use sui::coin_registry::{Self, CoinRegistry};

// Total supply of the `DEFLATIONARY_SUPPLY` coin is 1B (with 6 decimals).
const TOTAL_SUPPLY: u64 = 1000000000_000000;

// The type identifier of coin. The coin will have a type
// tag of kind: `Coin<package_object::currency::MyCoin>`
public struct MyCoin has key { id: UID }

#[allow(lint(self_transfer))]
/// Creates a new currency with a non-OTW proof of uniqueness.
public fun new_currency(registry: &mut CoinRegistry, ctx: &mut TxContext): Coin<MyCoin> {
let (mut currency, mut treasury_cap) = coin_registry::new_currency(
registry,
6, // Decimals
b"MyCoin".to_string(), // Symbol
b"My Coin".to_string(), // Name
b"Standard Unregulated Coin".to_string(), // Description
b"https://example.com/my_coin.png".to_string(), // Icon URL
ctx,
);

let total_supply = treasury_cap.mint(TOTAL_SUPPLY, ctx);
currency.make_supply_burn_only(treasury_cap);

let metadata_cap = currency.finalize(ctx);
transfer::public_transfer(metadata_cap, ctx.sender());

total_supply
}
Click to open

OTW currency creation

module examples::my_coin_new;

use sui::coin_registry;

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

// Module initializer is called once on module publish. A `TreasuryCap` is sent
// to the publisher, who then controls minting and burning. `MetadataCap` is also
// sent to the Publisher.
fun init(witness: MY_COIN_NEW, ctx: &mut TxContext) {
let (builder, treasury_cap) = coin_registry::new_currency_with_otw(
witness,
6, // Decimals
b"MY_COIN".to_string(), // Symbol
b"My Coin".to_string(), // Name
b"Standard Unregulated Coin".to_string(), // Description
b"https://example.com/my_coin.png".to_string(), // Icon URL
ctx,
);

let metadata_cap = builder.finalize(ctx);

// Freezing this object makes the metadata immutable, including the title, name, and icon image.
// If you want to allow mutability, share it with public_share_object instead.
transfer::public_transfer(treasury_cap, ctx.sender());
transfer::public_transfer(metadata_cap, ctx.sender());
}

초기화 프로세스는 다음을 허용한다:

  • Supply model selection: 고정, 소각 전용, 유연한 공급 중에서 선택한다.
  • Regulatory configuration: 필요하면 deny list capability를 추가한다.
Proper creation and RPC support requires a second transaction to promote the currency to the registry.

OTW 방법으로 통화를 초기화한 후에는 Coin Registry가 추적할 수 있는 shared Currency object를 생성하기 위해 coin_registry::finalize_registration을 반드시 호출해야 한다.

DenyList

Sui framework는 DenyCapV2 보유자가 Sui core type을 사용할 수 없는 address 목록을 지정할 수 있도록 DenyList singleton shared object를 제공한다. 그러나 DenyList의 초기 사용 사례는 지정된 타입의 코인에 대한 접근을 제한하는 데 초점을 맞춘다. 이는 예를 들어 특정 address가 transaction 입력으로 사용하는 것을 차단할 수 있어야 하는 Sui 규제된 코인(regulated coin)을 만들 때 유용하다. Sui의 규제된 코인은 알려진 악의적 행위자가 해당 코인에 접근하지 못하게 해야 하는 모든 규제를 충족한다.

정보

DenyList object는 address 0x403을 가지는 system object이다. 이를 직접 생성할 수는 없다.

Create regulated currency

finalize()를 호출하기 전에 초기화 단계에서 make_regulated() 함수를 사용한다. 이는 Currency<T>에 deny list capability를 추가하고 레지스트리 시스템 내에서 규제 상태를 추적한다.

Click to open

Regulated currency creation

module examples::regcoin_new;

use sui::coin::{Self, DenyCapV2};
use sui::coin_registry;
use sui::deny_list::DenyList;

public struct REGCOIN_NEW has drop {}

fun init(witness: REGCOIN_NEW, ctx: &mut TxContext) {
let (mut currency, treasury_cap) = coin_registry::new_currency_with_otw(
witness,
6, // Decimals
b"REGCOIN".to_string(), // Symbol
b"Regulated Coin".to_string(), // Name
b"Currency with DenyList Support".to_string(), // Description
b"https://example.com/regcoin.png".to_string(), // Icon URL
ctx,
);

// Claim `DenyCapV2` and mark currency as regulated.
let deny_cap = currency.make_regulated(true, ctx);
let metadata_cap = currency.finalize(ctx);
let sender = ctx.sender();

transfer::public_transfer(treasury_cap, sender);
transfer::public_transfer(metadata_cap, sender);
transfer::public_transfer(deny_cap, sender)
}
public fun add_addr_from_deny_list(
denylist: &mut DenyList,
denycap: &mut DenyCapV2<REGCOIN_NEW>,
denyaddy: address,
ctx: &mut TxContext,
) {
coin::deny_list_v2_add(denylist, denycap, denyaddy, ctx);
}

public fun remove_addr_from_deny_list(
denylist: &mut DenyList,
denycap: &mut DenyCapV2<REGCOIN_NEW>,
denyaddy: address,
ctx: &mut TxContext,
) {
coin::deny_list_v2_remove(denylist, denycap, denyaddy, ctx);
}

Create tokens

토큰은 sui::coin 모듈에 정의된 TreasuryCap을 재사용하므로 동일한 초기화 프로세스를 가진다. coin::create_currency 함수는 TreasuryCap의 고유성을 보장하고 CoinMetadata object의 생성을 강제한다.

코인과 유사한 함수가 토큰의 민팅과 소각을 수행한다. 둘 다 TreasuryCap이 필요하다:

  • token::mint: 토큰을 민트한다
  • token::burn: 토큰을 소각한다

토큰 작업에 대한 전체 세부 사항은 Closed-Loop Token standard를 참고한다.