로열티 토큰
Sui Closed-Loop Token standard를 사용하면, 항공사가 항공권이나 업그레이드를 구매하도록 상용 고객에게 token을 지급하고 싶어 하는 경우처럼, 특정 service에 대해서만 유효한 token을 생성할 수 있다.
이 예시에서 Admin은 지속적인 이용에 대한 보상으로 service 사용자에게 LOYALTY token을 보낸다. 예시는 holder가 LOYALTY token을 사용해 Gift를 구매할 수 있는 GiftShop을 만든다.
loyalty.move source file에는 loyalty token을 만드는 examples::loyalty module code가 들어 있다. 이 module에 는 coin을 생성하는 One-Time Witness(OTW)가 포함되어 있으며(이름은 module과 같은 LOYALTY), drop ability만 가지고 field는 없다.
/// The OTW for the Token / Coin.
public struct LOYALTY has drop {}
module의 init 함수는 LOYALTY OTW를 사용해 token을 생성한다. 이 함수는 앞서 정의한 OTW LOYALTY type을 사용해 create_currency를 호출한다. 또한 policy를 정의하고 policy capability와 treasury capability 둘 다 publish event와 연결된 address로 보낸다. 이 transferable capability의 holder는 새로운 LOYALTY token을 mint하고 policy를 수정할 수 있다.
init 함수는 package publish event 중에만 실행된다.
#[allow(deprecated_usage)]
fun init(otw: LOYALTY, ctx: &mut TxContext) {
let (treasury_cap, coin_metadata) = coin::create_currency(
otw,
0, // no decimals
b"LOY", // symbol
b"Loyalty Token", // name
b"Token for Loyalty", // description
option::none(), // url
ctx,
);
let (mut policy, policy_cap) = token::new_policy(&treasury_cap, ctx);
token::add_rule_for_action<LOYALTY, GiftShop>(
&mut policy,
&policy_cap,
token::spend_action(),
ctx,
);
token::share_policy(policy);
transfer::public_freeze_object(coin_metadata);
transfer::public_transfer(policy_cap, tx_context::sender(ctx));
transfer::public_transfer(treasury_cap, tx_context::sender(ctx));
}
LOYALTY minting 함수의 이름은 reward_user이다. TreasuryCap holder는 이 함수를 호출해 새 loyalty token을 mint할 수 있다. 이 함수는 token::mint 함수를 사용해 token을 생성하고 token::transfer를 사용해 의도한 recipient에게 보낸다.
public fun reward_user(
cap: &mut TreasuryCap<LOYALTY>,
amount: u64,
recipient: address,
ctx: &mut TxContext,
) {
let token = token::mint(cap, amount, ctx);
let req = token::transfer(token, recipient, ctx);
token::confirm_with_treasury_cap(cap, req, ctx);
}
마지막으로 buy_a_gift 함수는 LOYALTY token을 Gift type으로 redeem하는 작업을 처리한다. 이 함수는 gift 가격이 사용된 loyalty token 수와 일치하는지 확인한 다음 token::spend 함수를 사용해 treasury bookkeeping을 처리한다.
public fun buy_a_gift(token: Token<LOYALTY>, ctx: &mut TxContext): (Gift, ActionRequest<LOYALTY>) {
assert!(token::value(&token) == GIFT_PRICE, EIncorrectAmount);
let gift = Gift { id: object::new(ctx) };
let mut req = token::spend(token, ctx);
token::add_approval(GiftShop {}, &mut req, ctx);
(gift, req)
}