자산 토큰화
자산 토큰화는 부동산, 예술품, 원자재, 주식, 또는 그 밖의 가치 있는 자산과 같은 실물 자산을 blockchain network의 디지털 token으로 표현하는 과정을 의미한다. 이는 자산의 ownership 또는 권리를 디지털 token으로 변환하고, 그 token을 blockchain에 기록하고 관리하는 과정을 포함한다.
High-level overview
이 개념은 고가 자산을 더 작고 더 저렴한 단위로 나누어 자산의 ownership 또는 일부를 나타내는 것이다.
이 전략은 디지털 자산의 sole owner가 되는 대신 일부에 투자함으로써 위험을 완화하고자 하는 투자자들의 더 넓은 참여를 가능하게 하여, 더 폭넓은 투자자에게 접근성을 확장한다.
이 패턴은 추가 기능이 있는 ERC1155 multi-token standard와 유사하다. 이는 Sui에서 구현하고자 하는 Solidity 기반 사용 사례에 적합한 선택이 되게 한다.
-
Asset creation
각 자산은 총 공급량으로 분할되며, 각 분할분은 대체 불가능 토큰(NFT) 또는 대체 가능 토큰(FT) type collectible로 표현된다. 이는 각 개별 분할분이 1 이상과 같은 잔액을 유지하고, 모든 분할분을 합치면 자산의 총 공급량에 도달하도록 보장한다.
총 공급량 외에도 각 자산은 이름, 설명 등 다양한 다른 field로 정의된다. 이러한 field는 함께 자산의 metadata를 형성하며, 자산의 모든 분할분 전반에 걸쳐 일관되게 유지된다.
-
NFTs vs FTs distinction
tokenized asset가 mint될 때마다 시스템은 이를 새로운 metadata와 함께 생성할 수 있다. 새로운 metadata가 포함되면 tokenized asset는 고유해져 NFT로 바뀐다. 이 경우 잔액은 1로 제한되며, 이는 이 자산의 단일 instance만 존재함을 의미한다.
추가 metadata가 없으면 시스템은 tokenized asset를 FT로 분류하여 잔액이 1을 초과하도록 허용하고, 따라서 동일한 자산의 동일한 instance가 여러 개 존재할 수 있게 한다.
FT는 잔액이 1보다 클 때 서로 병합(join)되거나 분할될 수 있는 능력을 가진다. 이 기능은 필요에 따라 token unit을 집계하거나 분할할 수 있게 하여 다양한 수량을 유연하게 처리할 수 있게 한다.
앞서 언급했듯 tokenized asset의 모든 collectible은 NFT이든 FT이든 합치면 자산의 최대 총 공급량에 도달할 수 있다.
-
Burnability
자산을 생성할 때 자산의 분할분이 circulation에서 제거되거나 파괴될 수 있는지 정의할 수 있다. 자산을 제거하거나 파괴하는 과정을 burning이라고 한다.
tokenized asset가 burnable이면, 분할분을 burn할 때 circulating supply는 burn된 item의 잔액만큼 감소한다. 그러나 total supply는 일정하게 유지되므로, 필요하다면 burn된 분할분을 다시 mint하여 자산의 미리 정해진 total supply를 유지할 수 있다.
Move packages
Sui의 모든 스마트 계약과 마찬가지로 Move는 자산 토큰화를 구동하는 logic을 제공한다.
asset_tokenization package
이 reference implementation은 tokenized asset가 정의된 policy 안에서 동작하도록 보장하기 위해 Kiosk standard를 사용한다. royalty, commission 등의 rule을 지원하는 marketable tokenized asset를 가지려면 구현을 제시된 그대로 사용한다.
Kiosk가 요구 사항이 아니라면 unlock module과 transfer policy에 관련된 proxy method 일부를 제외할 수 있다.
세부사항을 보려면 module을 선택한다:
- tokenized_asset
- proxy
- unlock
tokenized_asset module은 coin library와 유사한 방식으로 동작한다.
이 module은 새로운 One-Time Witness type을 받으면 분할 자산의 고유 표현을 생성한다. 이 module은 Coin module에 있는 일부 method와 유사한 구현을 사용한다. 이 module은 새로운 자산 생성, minting, splitting, joining, burning을 포함해 자산 토큰화와 관련된 기능을 포괄한다. 자세한 정보는 The Move Book의 One Time Witness를 참조한다.
Structs
-
AssetCap분할 NFT로 표현되는 각 새 자산에 대해
AssetCap을 생성한다. 대부분의 시나리오에서는 이를 owned object로 생성한 뒤, 접근 제한된 method 호출을 위해 플랫폼 administrator에게 transfer할 수 있다.struct AssetCap<phantom T> {
id: UID,
// 현재 circulation 중인 supply
supply: Supply<T>,
// 어느 시점에든 존재하도록 허용되는 최대 total supply
total_supply: u64,
// 자산을 burn할 수 있는지 여부를 결정한다
burnable: bool
} -
AssetMetadataAssetMetadatastruct는 분할하려는 전체 자산을 나타내는 metadata를 정의한다. 이는 shared object여야 한다.struct AssetMetadata<phantom T> has key, store {
id: UID,
/// 자산의 이름
name: String,
// 어느 시점에든 존재하도록 허용되는 최대 total supply
total_supply: u64,
/// 자산의 symbol
symbol: ascii::String,
/// 자산의 설명
description: String,
/// 자산 logo의 URL
icon_url: Option<Url>
} -
TokenizedAssetTokenizedAsset는 남은 supply보다 작거나 같은 지정 잔액으로 mint된다. 자산의VecMap이 값으로 채워져 있어 여러 고유 entry를 나타내면 NFT로 간주한다. 반대로 자산의VecMap이 채워져 있지 않아 개별 entry가 없음을 나타내면 FT로 간주한다.struct TokenizedAsset<phantom T> has key, store {
id: UID,
/// tokenized asset의 잔액
balance: Balance<T>,
/// VecMap이 채워져 있으면 NFT로 간주하고, 그렇지 않으면 자산을 FT로 간주한다.
metadata: VecMap<String, String>,
/// 자산 image의 URL(optional)
image_url: Option<Url>,
} -
PlatformCapPlatformCap은 contract를 배포하는 개인에게 발행되는 capability를 의미한다. 이 capability는 플랫폼 기능에 관련된 특정 permission 또는 authority를 부여하여, deployer가 배포된 contract 내에서 특정 제어된 action 또는 access right를 갖게 한다./// contract를 배포하는 사람에게 발행되는 capability
struct PlatformCap has key, store { id: UID }
Functions
-
init이 함수는
PlatformCap을 생성하고 이를 transaction sender에게 transfer한다.fun init(ctx: &mut TxContext) {} -
new_asset이 함수는 자산의 새로운 표현을 생성하고 그 핵심 속성을 정의하는 책임을 가진다. 실행되면
AssetCap과AssetMetadata라는 2개의 distinct object를 반환한다. 이 object는 시스템 내에서 자산을 정의하는 데 필요한 정보와 특성을 캡슐화한다.public fun new_asset<T: drop>(
witness: T,
total_supply: u64,
symbol: ascii::String,
name: String,
description: String,
icon_url: Option<Url>,
burnable: bool,
ctx: &mut TxContext
): (AssetCap<T>, AssetMetadata<T>) {} -
mint이 함수는 tokenized asset의 minting을 수행한다. 이 과정에서 새로운 metadata가 도입되면 tokenized asset는 고유해져 잔액이 1로 설정된 NFT가 생성된다. 반대로 새로운 metadata가 추가되지 않으면 시스템은 tokenized asset를 FT로 분류하고 제공된 인자에 지정된 대로 그 잔액이 1을 초과할 수 있게 허용한다. 실행되면 함수는 tokenized asset object를 반환한다.
public fun mint<T>(
cap: &mut AssetCap<T>,
keys: vector<String>,
values: vector<String>,
value: u64,
ctx: &mut TxContext
): TokenizedAsset<T> {} -
split이 함수는 FT type의 tokenized asset 하나와 1보다 큰 잔액, 그리고 object의 잔액보다 작은 값을 받아 tokenized asset에 split operation을 수행한다. 이 operation은 기존 tokenized asset를 2개의 개별 tokenized asset로 나눈다. 새로 생성된 tokenized asset는 주어진 값과 같은 잔액을 가지며, 제공된 object의 잔액은 지정된 값만큼 감소한다. 완료되면 함수는 새로 생성된 tokenized asset를 반환한다. 이 함수는 NFT type의 tokenized asset를 받거나 작동하지 않는다.
public fun split<T>(
self: &mut TokenizedAsset<T>,
split_amount: u64,
ctx: &mut TxContext
): TokenizedAsset<T> {} -
join이 함수는 FT type의 tokenized asset 2개를 받아 tokenized asset에 merge operation을 실행한다. 이 operation은 첫 번째 tokenized asset의 잔액을 두 번째 tokenized asset의 잔액만큼 증가시키는 것을 포함한다. 이후 시스템은 두 번째 tokenized asset를 burn하거나 circulation에서 제거한다. 과정이 끝나면 함수는 burn된 tokenized asset의 ID를 반환한다.
이 함수는 NFT type의 tokenized asset를 받거나 작동하지 않는다.
public fun join<T>(
self: &mut TokenizedAsset<T>,
other: TokenizedAsset<T>
): ID {} -
burn이 함수는
assetCap을 parameter로 요구하여 호출을 플랫폼 admin으로만 제한한다. 추가로 operation의 일부로 burn되는 tokenized asset를 받는다. 제공된 tokenized asset를 burn하면 circulating supply는 burn된 item의 잔액만큼 감소한다. 이 함수는 burnable한 tokenized asset를 요구한다.public fun burn<T>(
cap: &mut AssetCap<T>,
tokenized_asset: TokenizedAsset<T>
) -
total_supply이 함수는 자산의 최대 supply를 반환한다.
public fun total_supply<T>(cap: &AssetCap<T>): u64 {} -
supply이 함수는 자산의 현재 circulating supply를 반환한다.
public fun supply<T>(cap: &AssetCap<T>): u64 {} -
value이 함수는 tokenized asset의 잔액을 반환한다.
public fun value<T>(tokenized_asset: &TokenizedAsset<T>): u64 {} -
create_vec_map_from_arrays이 internal helper 함수는
VecMap<String, String>를 채운다. 이는VecMapdata structure 안에서 key-value pair를 채우거나 설정하는 과정을 돕는다.fun create_vec_map_from_arrays(
keys: vector<String>,
values: vector<String>
): VecMap<String, String> {}
proxy module은 type owner가 publisher 관련 operation을 실행하는 데 사용하는 method로 구성된다.
Structs
-
ProxyPROXYstruct는 publisher를 claim하기 위한 One-Time Witness (OTW)를 나타낸다.struct PROXY has drop {} -
Registry이 shared object는
Publisherobject를 위한 repository 역할을 하며, 특히 tokenized asset에 대한 transfer policy 생성 및 관리를 제어하고 제한하는 용도로 의도되었다. 이 object에 대한 mutable access는 실제 publisher에게만 독점적으로 허용된다.struct Registry has key {
id: UID,
publisher: Publisher
} -
ProtectedTP이는 비어 있는 transfer policy를 저장하는 shared object이다. 사용자가 생성한 각 type
<T>마다 하나씩 생성해야 한다. 이 object의 관여는 unlock module에서 드러난다.struct ProtectedTP<phantom T> has key, store {
id: UID,
policy_cap: TransferPolicyCap<T>,
transfer_policy: TransferPolicy<T>
}
Functions
-
init이 함수는
Publisherobject를 생성하고 이를 registry 안에 캡슐화한 뒤Registryobject를 share하는 책임이 있다.fun init(otw: PROXY, ctx: &mut TxContext) {} -
setup_tp이 함수는 registry 안에 중첩된 publisher와 sender의 publisher를 활용한다. 이는
TokenizedAsset<T>type 전용 transfer policy와 연관된 transfer policy cap을 생성하고 반환한다. 이 typeT는Publisherobject에서 파생된다.또한
ProtectedTP<T>object 안에 래핑된 비어 있는 transfer policy를 생성하고 이를 share한다. 이 기능은 특정 조건에서 Kiosk lock rule을 override하는 데 사용할 수 있다.public fun setup_tp<T: drop>(
registry: &Registry,
publisher: &Publisher,
ctx: &mut TxContext
): (TransferPolicy<TokenizedAsset<T>>,
TransferPolicyCap<TokenizedAsset<T>>) {} -
new_display이 함수는 registry 안에 중첩된 publisher와 sender의 publisher를 사용해
Publisherobject 안에 캡슐화된T에 대해 typeTokenizedAsset<T>의 비어 있는Display를 생성하고 반환한다.public fun new_display<T: drop>(
registry: &Registry,
publisher: &Publisher,
ctx: &mut TxContext
): Display<TokenizedAsset<T>> {} -
transfer_policy이 함수는
protectedTP가 제공되면 typeTokenizedAsset<T>전용으로 설계된 transfer policy를 반환한다.public(friend) fun transfer_policy<T>(
protected_tp: &ProtectedTP<T>
): &TransferPolicy<T> {} -
publisher_mut이 함수는 platform cap owner만 접근할 수 있다. publisher에 대한 mutable reference를 얻기 위해 registry를 인자로 요구한다.
public fun publisher_mut(
_: &PlatformCap,
registry: &mut Registry
): &mut Publisher {}
unlock module은 authorized된 burning과 joining만을 위해 tokenized asset를 unlocking하는 것을 가능하게 한다.
이는 tokenized asset type creator가 rule이나 policy 같은 기본 requirement 집합을 따를 필요 없이 kiosk asset에 대해 이 operation을 가능하게 할 수 있게 한다.
Structs
-
JoinPromisejoin의 의도된 범위를 넘어 object를 영구적으로 unlock하려는 시도를 방지하기 위해 promise object를 설정한다.
struct JoinPromise {
/// burn된 tokenized asset의 잔액이 추가될 item이다.
item: ID,
/// burned는 burn될 tokenized asset의 id이다
burned: ID,
/// 병합 뒤 item의 기대 최종 잔액이다
expected_balance: u64
} -
BurnPromise지정된 object의 영구적인 burning을 보장하기 위해 생성되는 promise object이다.
struct BurnPromise {
expected_supply: u64
}
Functions
-
asset_from_kiosk_to_join이 helper 함수는 kiosk에 lock된 tokenized asset의 joining을 돕기 위해 의도되었다. 이는 burn 대상인 tokenized asset를 unlocking하는 것을 도우며, 같은 type의 다른 tokenized asset가 결국 그 잔액을 포함하게 될 것임을
JoinPromise를 반환함으로써 보장한다.public fun asset_from_kiosk_to_join<T>(
self: &TokenizedAsset<T>, // A
to_burn: &TokenizedAsset<T>, // B
protected_tp: &ProtectedTP<TokenizedAsset<T>>, // unlocker
transfer_request: TransferRequest<TokenizedAsset<T>> // b에 대한 transfer request
): JoinPromise {} -
prove_joinunlock된 tokenized asset가 성공적으로 burn되었고 그 잔액이 기존 tokenized asset에 통합되었음을 입증하는 데 사용하는 함수이다.
public fun prove_join<T>(
self: &TokenizedAsset<T>,
promise: JoinPromise,
proof: ID) {
} -
asset_from_kiosk_to_burnkiosk에 lock된 tokenized asset의 burning을 돕는 helper 함수이다. 이는 unlocking을 돕는 동시에 circulating supply가 감소할 것이라는 promise를
BurnPromise를 반환함으로써 보장한다.public fun asset_from_kiosk_to_burn<T>(
to_burn: &TokenizedAsset<T>,
asset_cap: &AssetCap<T>,
protected_tp: &ProtectedTP<TokenizedAsset<T>>,
transfer_request: TransferRequest<TokenizedAsset<T>>,
): BurnPromise {
} -
prove_burnasset cap의 circulating supply가 burn된 tokenized asset의 잔액만큼 줄어들도록 보장한다.
public fun prove_burn<T>(
asset_cap: &AssetCap<T>,
promise: BurnPromise) {
}
template package
브라우저에서의 매끄러운 자산 생성을 지원하기 위해 Rust Wasm 기능 활용을 가능하게 하는 예시 사용 사례 package이다.
이는 launchpad 접근 방식과 유사하며, 새 자산이 tokenized asset로 표현되어야 할 때마다 template package 역할을 한다.
실질적으로 이는 사용자가 이 template contract의 field를 즉석에서 편집하고 그 편집을 포함한 채 publish할 수 있게 한다. 이 package는 자산 토큰화에 필요한 구분된 기능에 대응하는 두 개의 essential module을 구현한다. Rust Wasm이 어떻게 구현되었는지에 대한 자세한 내용은 Web Assembly 섹션에서 찾을 수 있다.
-
Modules
-
template이는 새 자산 정의를 지원하는 module이다.
새 자산을 분할 자산으로 표현해야 할 때 이 module을
<template>::<TEMPLATE>로 수정하는데, 여기서<template>(대문자)는 이 새 자산의 OTW이다.이 module은 자산에 대한 새 field 선언을 돕는
asset_tokenization::tokenized_asset::new_asset(...)method를 호출한다:witness: OTWNEW_ASSETtotal_supply: 어느 시점에든 존재하도록 허용되는 total supplysymbol: 자산의 symbolname: 자산의 이름description: 자산의 설명icon_url: 자산 logo의 URL(optional)burnable: 자산을 admin이 burn할 수 있는지 정의하는 Boolean
-
genesissender가 publisher를 claim할 수 있도록 OTW를 포함하는 genesis type의 module이다.
-
Publish and mint tokenized sequence diagram
Join sequence diagram
다음 sequence diagram은 join flow가 어떻게 진행되는지 보여준다. 다음 flow는 다음을 가정한다:
- tokenized asset X와 Y는 type creator에 의해 이미 mint되었다.
- tokenized asset X와 Y는 이미 사용자의 kiosk 안에 배치되고 lock되었다.
- 모든 것은 같은 programmable transaction block(PTB)에서 실행된다.
Burn sequence diagram
다음 sequence diagram은 burn flow를 보여주며 다음을 가정한다:
- tokenized asset는 type creator에 의해 이미 mint되었다.
- tokenized asset는 이미 사용자의 Kiosk 안에 배치되고 lock되었다.
- 모든 것은 같은 PTB에서 실행된다.
Variations
제공된 package와 module은 프로젝트에 맞게 자산 토큰화를 구현할 수 있는 방법을 보여준다. 특정 사용 사례는 편의를 위해 contract를 변경하거나 새 기능을 도입하도록 요구할 가능성이 높다.
Example convenience alteration
PTB 안에서 여러 단계로 unlock 기능을 구현하는 대신, 자산의 purchase, borrowing, unlocking, joining을 한 함수 안에서 모두 수행하는 method를 만드는 것도 가능하다. joining operation에 대해 이것이 어떻게 보이는지는 다음과 같다:
public fun kiosk_join<T>(
kiosk: &mut Kiosk,
kiosk_cap: &KioskOwnerCap,
protected_tp: &ProtectedTP<TokenizedAsset<T>>,
ta1_id: ID,
ta2_id: ID,
ctx: &mut TxContext
) {
kiosk::list<TokenizedAsset<T>>(kiosk, kiosk_cap, ta2_id, 0);
let (ta1, promise_ta1) = kiosk::borrow_val(kiosk, kiosk_cap, ta1_id);
let coin = coin::zero<SUI>(ctx);
let (ta2, request) = kiosk::purchase(kiosk, ta2_id, coin);
let tp_ref = proxy::transfer_policy(protected_tp);
let (_item, _paid, _from) = transfer_policy::confirm_request(
tp_ref,
request
);
tokenized_asset::join(&mut ta1, ta2);
kiosk::return_val(kiosk, ta1, promise_ta1);
}
Example alteration for use case
다음 예시는 AssetCap<T>를 두 개의 새 object인 Treasury<T>와 AdminCap<T>로 분리한다(사실상 대체한다). 원래 package에 정의된 method에 대한 access는 이제 이 변경이 원치 않는 효과를 도입할 수 있으므로 주의 깊게 다시 설계해야 한다. 이 필수적인 재설계는 이 예시에 완전히 포함되어 있지 않으며, 시연 목적(또는 심화 연습)으로 일부 method만 변경된다.
사용자도 admin뿐 아니라 자산을 burn할 수 있게 하고 싶다고 가정해 보자. 이것은 여전히 authorized된 operation이어야 하지만, 특정 사용 사례 목적(예: 모은 collectible 전부를 burn해 결합하는 경우)을 위해 tokenized asset를 소비하는 유연성을 제공한다. 이를 달성하기 위해 admin은 burn할 수 있는 자산의 ID를 담은 ticket를 mint할 수 있다. 이 기능을 지원하려면 smart contract를 재설계하고 admin을 각 자산의 treasury와 분리해야 하며, 이 treasury는 이제 supply 관련 정보만 보유한다. 발생해야 하는 변경의 예시는 다음과 같다:
Structs
receiver가 이를 거래할 수 없도록 key ability만 가진 ticket를 만든다.
struct BurnTicket<phantom T> has key {
id: UID,
tokenized_asset_id: ID // 이 ticket로 burn access를 얻는 tokenized asset
}
이제 treasury 관련 정보만 보유하는 struct(AssetCap를 분할한 결과이므로 더는 이 설계의 일부가 아니다)는 shared object로 생성된다. mint 같은 함수도 이제 Treasury object와 AdminCap object를 모두 입력으로 받도록 변경한다.
struct Treasury<phantom T> has key, store {
id: UID,
supply: Supply<T>,
total_supply: u64,
}
AssetCap 기능의 다른 절반으로 burnability 설정과 admin capability를 유지하는 owned object는 type <T>의 creator에게 전송된다.
struct AdminCap<phantom T> has key, store {
id: UID,
burnable: bool
}
Method Signatures
여기서 AdminCap은 admin capability이자 type insurance 둘 다 역할을 한다. 이 ticket로 삭제할 수 있도록 허용되는 자산 type의 정보 둘 다를 인코딩한다.
이 함수는 자산 T가 burnable임을 assert하고 BurnTicket<T>를 반환해야 한다.
public fun mint_burn_ticket<T>(
cap: &AdminCap<T>,
tokenized_asset_id: ID,
ctx: &mut TxContext
): BurnTicket
사용자 측의 burning은 그들이 shared Treasury object에 접근하도록 요구한다. 이 함수는 tokenized asset를 burn하고 supply를 감소시킨다.
public fun burn_with_ticket<T>(
treasury: &mut Treasury<T>,
self: TokenizedAsset<T>,
ticket: BurnTicket<T>)
Deployment
See "Hello, World!" for a more detailed guide on publishing packages or Sui Client CLI for a complete reference of client commands in the Sui CLI.
Before publishing your code, you must first initialize the Sui Client CLI, if you haven't already. To do so, in a terminal or console at the root directory of the project enter sui client. If you receive the following response, complete the remaining instructions:
Config file ["<FILE-PATH>/.sui/sui_config/client.yaml"] doesn't exist, do you want to connect to a Sui full node server [y/N]?
Enter y to proceed. You receive the following response:
Sui full node server URL (Defaults to Sui Testnet if not specified) :
Leave this blank (press Enter). You receive the following response:
Select key scheme to generate key pair (0 for ed25519, 1 for secp256k1, 2: for secp256r1):
Select 0. Now you should have a Sui address set up.
Publishing
이 단계에서는 contract를 수동으로 배포할지, 아니면 contract를 자동으로 배포하고 .env의 Asset Tokenization 관련 field 대부분을 설정해 주는 publish bash script를 사용할지 선택할 수 있다.
.env.template file은 script가 자동으로 채우는 변수를 나타낸다.
다음 reference를 볼 수 있다:
SUI_NETWORK = 선택한 network의 rpc endpoint | publish script가 자동 채움
ASSET_TOKENIZATION_PACKAGE_ID = `asset_tokenization` package를 publish해 생성됨 | publish script가 자동 채움
REGISTRY = `asset_tokenization` package를 publish해 생성됨 | publish script가 자동 채움
TEMPLATE_PACKAGE_ID = `template` package를 publish해 생성됨
ASSET_CAP_ID = `template` package를 publish해 생성됨
ASSET_METADATA_ID = `template` package를 publish해 생성됨
ASSET_PUBLISHER = `template` package를 publish해 생성됨
PROTECTED_TP = `setup_tp` 함수를 호출해 생성됨
TRANSFER_POLICY = `setup_tp` 함수를 호출해 생성됨
OWNER_MNEMONIC_PHRASE = 자신의 mnemonic | publish 전에 terminal에서 로컬로 export할 수 있음
BUYER_MNEMONIC_PHRASE = buyer의 mnemonic | publish 전에 terminal에서 로컬로 export할 수 있음
TARGET_KIOSK = kiosk id
BUYER_KIOSK = kiosk id
TOKENIZED_ASSET = tokenized asset id(minting으로 생성됨)
FT1 = tokenized asset id(join 대상)
FT2 = tokenized asset id(join 대상)
publishing에 대한 자세한 내용은 setup folder의 README를 확인한다.
Publishing packages
구체적인 지침은 package를 선택한다.
Beginning with the Sui v1.24.1 release, the --gas-budget option is no longer required for CLI commands.
- asset_tokenization
- template
Manually
프로젝트의 move/asset_tokenization directory에서 terminal 또는 console에 다음을 입력한다:
$ sui client publish --gas-budget <GAS-BUDGET>
gas budget에는 20000000 같은 표준 값을 사용한다.
package는 성공적으로 deploy되어야 하며, 그 뒤 다음을 보게 된다:
UPDATING GIT DEPENDENCY https://github.com/MystenLabs/sui.git
INCLUDING DEPENDENCY Sui
INCLUDING DEPENDENCY MoveStdlib
BUILDING asset_tokenization
Successfully verified dependencies on-chain against source.
또한 많은 정보와 transactional effect를 볼 수 있다.
생성된 object에서 package ID와 registry ID를 선택하여 자신의 .env file 각 field에 저장해야 한다.
이후 Move.toml file을 수정해야 한다. [addresses] 섹션 아래의 0x0를 같은 package ID로 바꾼다. 선택적으로 [package] 섹션 아래에 published-at = <package ID>를 추가한다(sui client publish를 실행한 뒤 Move.lock file이 보인다면 이 단계는 필요하지 않다).