본문으로 건너뛰기

대체 가능 토큰 만들기: Coin Standard

Coin standard는 sui::coin module을 사용해 keystore ability를 가진 coin이라는 fungible asset을 정의한다. coin은 wrapping과 public transfer functionality를 지원한다.

Coin<T> type은 type parameter T로 denomination되는 open-loop fungible token을 나타내며, T는 모든 Coin<T> instance에 적용되는 metadata와도 연관된다. sui::coin module은 Coin<T>를 fungible로 취급하는 interface를 노출한다. 즉 전통적인 fiat currency와 유사하게, 한 Coin<T> instance가 보유한 T unit은 다른 어떤 T unit과도 interchangeable하다.

network native coin인 SUI는 Coin standard를 사용한다.

Coin standard 사용

coin을 만들려면 metadata를 정의하고, currency를 만들고, initial supply를 mint해야 한다.

Step 1: metadata 정의

coin의 name, description, symbol, icon URL, decimals를 포함한 metadata를 정의한다.

이 예시는 decimals 9개, name Silver, description, symbol SILVER, Walrus에 저장된 asset용 icon URL을 가진 coin을 만든다.

Step 2: currency 생성

coin::create_currency function을 사용해 coin을 생성한다.

Step 3: initial supply mint

coin의 initial supply를 mint한다.

전체 예시 보기 또는 Coin Standard에 대해 더 알아본다.

coin 관리

Sui는 fungible asset을 보유하는 두 가지 방식을 지원한다: 주소 잔액과 coin object. 대부분의 use case에는 주소 잔액을 default로 권장한다. coin object는 explicit object-level control이 필요한 scenario에서 계속 사용할 수 있다.

주소 잔액

주소 잔액은 각 coin type에 대해 Sui address에 직접 연결된 canonical balance를 제공한다. send_funds를 통해 전송된 funds는 object management 없이 coin type별 단일 balance로 자동 merge된다.

주소 잔액의 주요 이점:

  • coin selection 또는 merging logic이 필요 없다.
  • object state를 query하지 않는 stateless transaction construction.
  • SUI 주소 잔액에서 gas payment 직접 지불.
  • 여러 deposit이 자동으로 merge된다.

TypeScript SDK(v2+)는 기본적으로 주소 잔액을 사용한다. coinWithBalance를 사용하면 SDK는 먼저 주소 잔액에서 인출하고 필요할 때만 coin object로 fallback한다. gas payment의 경우 setGasPayment에 empty array를 전달해 주소 잔액에서 지불한다.

withdrawal pattern, gas payment, sponsored transaction, balance query를 포함해 주소 잔액 사용에 대한 전체 reference는 주소 잔액 마이그레이션 가이드를 참조한다.

Coin object

Coin object는 주어진 coin type의 특정 amount를 나타내는 address-owned object이다. 주소 잔액 이전에는 Sui의 모든 funds가 coin object로 보관되었다. coin object는 계속 완전히 동작하며 deprecated되지 않았다.

coin object는 다음 상황에서 유용하다.

  • Coin<T> 또는 &mut Coin<T>를 기대하는 Move function에 직접 전달해야 한다.
  • 다른 object 안에 funds를 보관해야 한다(예: shared escrow 또는 liquidity pool).
  • transaction에 사용되는 정확한 object set을 제어해야 한다.

coin object는 owned object이므로 highly parallel transaction execution을 가능하게 한다. 각 coin은 자체 version을 가진 independent object이므로 서로 다른 coin을 touch하는 transaction은 contention 없이 concurrently execute될 수 있다.

PTB 안에서 explicit coin manipulation을 하려면 mergeCoins command로 여러 coin object를 하나로 combine하고, splitCoins로 coin을 더 작은 조각으로 나눈다. 이 operation은 inexpensive하지만 coin distribution과 transaction need를 알고 있어야 한다.

coin object accumulation

시간이 지나며 많은 coin object가 accumulate되는 것은 흔하다. 특히 frequent transfer를 받는 경우 그렇다. 일부 scenario에서는 coin을 single object로 merge해야 한다. 예를 들어 transaction을 cover할 만큼 충분한 value를 가진 single coin이 없다면 먼저 coin을 merge해야 한다.

coin::send_funds를 자신의 address를 recipient로 하여 호출하면 언제든 coin object를 주소 잔액으로 변환할 수 있다. 지침은 기존 Coin을 주소 잔액으로 변환을 참조한다.

Gas smashing

transaction을 execute할 때 single coin이 아니라 여러 coin을 gas payment로 제공할 수 있다. gas smashing이라고 하는 이 feature는 제공된 coin을 payment vector의 첫 번째 coin으로 자동 merge한다. merge된 coin에서 gas budget을 뺀 나머지는 transaction 안에서 어떤 command에도 사용할 수 있다. 사용하지 않으면 sender에게 반환된다.

Gas smashing은 Coin<SUI> object에만 적용된다. SUI가 gas payment로 accepted되는 유일한 coin type이기 때문이다.

coin은 원하는 만큼 제공할 수 있다(protocol configuration에 정의된 maximum까지). Gas smashing은 transaction의 일부로 SUI coin을 consolidate해야 할 때 유용한 tool이다.

주소 잔액 gas payment를 사용한다면(empty gas payment array 전달) gas smashing이 필요 없다. 주소 잔액 gas payment는 gas coin을 select하거나 merge할 필요를 완전히 제거한다.

자세한 내용은 Gas Smashing을 참조한다.

Concurrency

주소 잔액은 대부분의 use case에서 concurrency challenge를 크게 줄인다. 주소 잔액 gas payment는 owned object input을 필요로 하지 않으므로 object version conflict나 locking을 걱정하지 않고 여러 transaction을 build하고 sign할 수 있다.

concurrency가 여전히 중요한 경우

transaction이 coin object(또는 다른 owned object)를 input으로 사용하면 기존 concurrency constraint가 적용된다. 각 owned object에는 version이 있으며, transaction에 sign하면 system이 이를 lock한다. 이 lock은 첫 번째 transaction이 execute될 때까지 같은 object를 다른 transaction에서 사용하는 것을 방지한다. 같은 owned object로 여러 transaction에 sign하려고 하면 equivocation이 발생할 수 있고, 그러면 epoch가 끝날 때까지 object를 사용할 수 없게 된다.

coin object로 heavy concurrency가 필요한 경우 concurrently execute할 transaction 수만큼 coin을 split한다. 또는 각 transaction에 서로 다른 coin을 제공한다(gas smashing을 통해). concurrent transaction 전반에서 사용되는 coin set은 overlap이 없어야 한다.

권장 approach

대부분의 application에서는 gas payment와 fund transfer에 주소 잔액을 사용한다. Coin object management는 Move contract가 Coin<T> argument를 요구하거나 owned object를 명시적으로 제어해야 하는 경우에만 남겨둔다. 이 approach는 concurrency issue를 최소화하고 transaction construction을 단순화한다.