Spending
Because Token
type does not have the store
ability, it is impossible to "store" it in another object. Hence, Coin-like approaches to spending are not possible - an application that takes Token
as a payment won't be able to add it to its balance. To address this issue, Token
has a "spend" method, which allows "spending" it in one application and then delivering it as a spent_balance
to the TokenPolicy or burning right away with a TreasuryCap
.
Spend Action
Token
can be spent by calling the spend
method. It takes the following arguments:
// module sui::token
public fun spend<T>(token: Token<T>, ctx: &mut TxContext): ActionRequest<T>;
As you can see from the signature, the Token
object is consumed. Its balance becomes the spent_balance
in the ActionRequest.
Spent Token
The ActionRequest
for the "spend" action contains the Balance
of the spent Token
, and it can either be confirmed with a TreasuryCap
or delivered to the TokenPolicy. In the first case, the Balance will be "burned" directly in the TreasuryCap
, and in the second case, it will be delivered to the TokenPolicy's "spent_balance".
Spent balance cannot be used in any way, and it is not possible to "withdraw" it. The only available action is "flushing" - burning the spent_balance
by bringing a TreasuryCap
.
Gating the Spend Action
Normally, the spend
action should have at least one "Rule" assigned to it to prevent aimless spending, and the recommended way of authorizing the spend in an application that accepts the Token is to "stamp" it right in the function where a spend is performed. For example:
/// Rule-like witness to stamp the ActionRequest
struct GiftShop has drop {}
/// Spend the token and return a Gift + ActionRequest
public fun buy_gift(
token: Token<CREDITS>,
ctx: &mut TxContext
): (Gift, ActionRequest<CREDITS>) {
// token is spent
let action_request = token::spend(token, ctx);
// stamp the ActionRequest as performed by GiftShop
token::add_approval(GiftShop {}, &mut action_request, ctx);
// return already "stamped" ActionRequest
(Gift { ... }, action_request)
}