지출
Token 타입은 store ability를 가지지 않기 때문에 이를 다른 object에 저장하는 것은 불가능하다. 따라서 Coin과 유사한 지출 방식은 사용할 수 없다. 결제를 위해 Token을 받는 애플리케이션은 이를 자신의 잔액에 추가할 수 없다. 이 문제를 해결하기 위해 Token은 spend 메서드를 가지며, 이를 통해 하나의 애플리케이션에서 지출한 뒤 spent_balance로 TokenPolicy에 전달하거나 TreasuryCap을 사용해 즉시 소각할 수 있다.
Spend action
spend 메서드를 호출하여 Tokens를 지출할 수 있다. 이 메서드는 다음 인자를 받는다:
// module sui::token
public fun spend<T>(token: Token<T>, ctx: &mut TxContext): ActionRequest<T>;
시그니처에서 보이듯이 Token object는 소비된다. 그 잔액은 ActionRequest의 spent_balance가 된다.
Spent token
spend의 실행에 대한 ActionRequest는 지출된 Token의 Balance를 포함하며, 이는 TreasuryCap과 함께 확정하거나 TokenPolicy에 전달할 수 있다. 첫 번째 경우 잔액은 TreasuryCap에서 직접 소각되며, 두 번째 경우에는 TokenPolicy의 spent_balance로 전달된다.
Spent balance는 어떤 방식으로도 사용할 수 없으며 이를 인출하는 것도 불가능하다. 유일하게 가능한 동작은 flushing이며, 이는 TreasuryCap을 가져와 spent_balance를 소각하는 것이다.
Gating the spend action
일반적으로 spend의 실행에는 목적 없는 지출을 방지하기 위해 최소 하나의 규칙이 할당되어야 하며, 토큰을 수락하는 애플리케이션에서 지출을 승인하는 권장 방식은 지출이 수행되는 함수 내에서 이를 직접 스탬프하는 것이다. 예를 들어:
/// `ActionRequest`를 stamp하기 위한 Rule 유사 witness
struct GiftShop has drop {}
/// 토큰을 사용하고 Gift + ActionRequest를 반환한다
public fun buy_gift(
token: Token<CREDITS>,
ctx: &mut TxContext
): (Gift, ActionRequest<CREDITS>) {
// 토큰을 사용한다
let action_request = token::spend(token, ctx);
// GiftShop이 수행한 것으로 `ActionRequest`를 stamp한다
token::add_approval(GiftShop {}, &mut action_request, ctx);
// 이미 stamp된 ActionRequest를 반환한다
(Gift { ... }, action_request)
}