Skip to content

XSC-0001: Fungible Token

XSC-0001 is the core fungible-token interface used across the Xian stack.

Required Surface

The standard token surface is:

python
@export
def change_metadata(key: str, value: Any):
    ...

@export
def transfer(amount: float, to: str):
    ...

@export
def approve(amount: float, to: str):
    ...

@export
def transfer_from(amount: float, to: str, main_account: str):
    ...

@export
def balance_of(address: str) -> float:
    ...

Expected Semantics

  • transfer moves balance from ctx.caller to to
  • approve sets an allowance for to
  • transfer_from spends from main_account using the caller's allowance
  • balance_of returns the current balance for an address

The current canonical implementation stores allowances in a dedicated approvals hash using a two-dimensional key:

python
approvals[owner, spender] = amount

Expected Events

The canonical token contract emits:

  • Transfer
  • Approve

Typical indexed fields are sender and recipient/spender so that CometBFT and dashboard subscribers can query them efficiently.

python
balances = Hash(default_value=0)
approvals = Hash(default_value=0)
metadata = Hash()

Common metadata keys in the canonical token are:

  • token_name
  • token_symbol
  • token_logo_url
  • token_logo_svg
  • token_website
  • total_supply
  • operator
  • permit_authorizer

Wallets should prefer token_logo_url when it is present and non-empty. If the URL field is empty, they should fall back to token_logo_svg and render the on-chain SVG directly.

The canonical currency contract treats metadata in two classes:

  • display metadata, such as name, symbol, logo, and website, can be changed by metadata["operator"] through change_metadata
  • sensitive metadata, such as total_supply, operator, and permit_authorizer, is not writable through change_metadata

total_supply is managed by token accounting. The canonical currency contract exposes governance-only helpers for sensitive authority changes:

python
@export
def set_operator(new_operator: str):
    ...

@export
def set_permit_authorizer(new_authorizer: str):
    ...

Tokens that support XSC-0002 Permit Authorizer should keep the permit-authorizer contract name in token state and guard approve_from_authorizer(...) against all other callers.

Compatibility Notes

  • validate amount > 0 for transfers
  • approvals may be 0 and should overwrite prior allowance
  • emit events on successful transfer/approval paths
  • keep function names and argument names stable so tooling can introspect them