Non-EVM Standards

Tezos FA2 (TZIP-012)

Understand Tezos FA2 (TZIP-012), the multi-asset token standard enabling fungible, non-fungible and compliant tokens on Tezos.

Last updated: 12/29/2025
Improve this page

Tezos FA2 (TZIP-012), the multi-asset token standard on Tezos' self-amending blockchain, defines a unified smart contract interface for fungible, non-fungible, and hybrid tokens with batch operations and customizable permission policies. For Real World Asset (RWA) protocols, this standard is especially valuable, as tokens can represent fractional claims on tokenized art, real estate, commodities, or other off-chain collateral while maintaining a compliant, interoperable interface for transfers, balances, and operator approvals with built-in support for formal verification and on-chain governance.

Before FA2, Tezos RWA projects used fragmented FA1.2 contracts, leading to inconsistent multi-asset handling, siloed compliance, and integration challenges. FA2 resolved this by introducing token_id for multi-asset support and permission policies for regulatory gating, leveraging Tezos' liquid proof-of-stake for 1,000+ TPS and adaptive inflation. For RWA builders, the standard provides a verifiable abstraction layer supporting off-chain metadata (TZIP-016), oracle-fed policies, and asynchronous approvals, while enabling seamless composability with DeFi protocols like Quipuswap or Plenty.

A key design principle is policy-driven flexibility, where contracts expose standardized entrypoints augmented by optional permissions without exposing internal ledger logic. This is well suited to RWA tokens where transfers may depend on off-chain KYC or governance votes, yet integrators like wallets or aggregators still need reliable, auditable operations.

Use of FA2 in RWA Contexts

FA2 is the foundational standard for RWA tokens on Tezos because it abstracts the complexity of tokenizing and managing real-world assets into a multi-asset, policy-compliant framework. While traditional DeFi tokens use FA2 for unrestricted multi-token transfers, RWA tokens adapt the model to illiquid, regulated assets, tokenized private credit, commercial real estate, art, or bond portfolios, where on-chain tokens represent legally backed off-chain value held by custodians or SPVs, with permission policies for securities laws like Reg D or MiCA.

Key Applications in RWA Development

Fractional Ownership and Liquidity Provision

Many RWAs are high-value and indivisible (for example, a ten-million-dollar artwork or a portfolio of property stakes). FA2 allows developers to mint hybrid tokens (e.g., token_id 0 for fractions) proportional to deposits, unlocking fractional ownership and secondary-market liquidity under compliance rules.

  • Implement transfer batches with operator approvals to restrict to whitelisted holders.
  • Tokens can trade freely on DEXs like Quipuswap, offering liquidity for assets that would otherwise be locked for years.
  • Example: A real estate token where permission policy gates transfers to accredited investors, with token_id for share classes.

Yield Accrual and NAV Management

Operator approvals automate revenue distribution (e.g., rental yields from property tokens), with balance_of batches querying oracles (e.g., Chainlink) for real-time NAV updates. This supports auto-accrual without manual interventions, ideal for tokenized funds or art royalties.

Using trusted sources (Chainlink, Pyth) ensures accurate ledgers, critical for compliance and for investor queries. Regulators increasingly expect transparent ownership reporting, and FA2 provides this without exposing internal policy state.

Redemption and Settlement Mechanics

RWA redemptions are inherently asynchronous, as physical settlement layers (banks, custodians, transfer agents) cannot finalize instantly.

Patterns include:

  • transfer to burn address with policy for queued releases.
  • Operator revocations for invalid holdings.
  • Callback memos for signed claims.
  • Proof-of-reserve checks before fulfillment.

Composability Across the RWA Stack

FA2 tokens plug directly into Tezos DeFi:

  • Plenty accepts tokens as collateral within policy restrictions.
  • Quipuswap pairs can provide deep secondary liquidity for permitted transfers.
  • Aggregators (e.g., Kelp) route into FA2 natively.

For regulated RWAs:

  • Pair with custom policies for investor eligibility gating.
  • Combine with operators for modular compliance.
  • Integrate identity proofs via metadata.

This drastically reduces integration complexity, for example, a tokenized art token can list across lending markets without custom adapters.

Developer Advantages in RWA Builds

  • Regulatory Alignment: Permission policies hide off-chain custodian processes while preserving accurate operators for MiFID II/MiCA-aligned disclosures.
  • Extensibility: Batch entrypoints and TZIP-016 metadata allow injecting RWA-specific logic i.e., pricing oracles, geofencing, or IPFS-pinned compliance policies.
  • Risk Isolation: Tokens remain fully ledger compliant, revocations do not impact wallet-held balances outside policies.
  • Upgrade Path: Self-amending Tezos enables governance upgrades, preserving TVL and simplifying audits.

To visualize the end-to-end flow in an RWA token, the following sequence diagram captures the typical mint - transfer - query cycle. It illustrates how users interact with the FA2 contract, how policies interact with operators and oracles, and how off-chain compliance updates flow back on-chain through callbacks or metadata. This representation is especially important for understanding asynchronous transfers, delayed settlements, and policy-driven compliance in RWA systems.

Tezos.svg

This diagram highlights how FA2 acts as the connective tissue between on-chain token operations and off-chain asset realities. Mints use transfers from zero proportional to contributed value, policies capture real-world compliance as transfers execute, and callback functions help manage queries during audits. For illiquid RWA portfolios, the model can be extended with explicit operator rules between the contract (C) and the custodian or SPV (Cust) to handle delayed settlement cycles.

Core Specification

An FA2 contract must implement the core entrypoints for its multi-asset structure, the permissioned representation of a user’s proportional claim on the underlying asset. Optional policies enable advanced features like operator gating, a valuable enhancement for RWA use cases where institutions manage access without needing full custom logic.

In FA2, the contract behaves like any Tezos token (balance queries, total supply via views, transfers), while token_id refers to appended modules for collateral management. The specification enforces a clean separation between base ledgers and policy params, ensuring predictable operations and seamless integration across Tezos and RWA systems.

Key Definitions

  • Token ID: The nat identifier for asset types within the contract, e.g., 0 for fungible RWA shares or 1 for NFT deeds.
  • Ledger: The big_map storage for balances, extensible for single/multi-asset or NFT modes.
  • Total Supply: The aggregate token value managed by the contract, equal to the sum of principal, transferred amounts, and adjustments for fees or burns.
  • Permission Policies: (e.g., owner-only, operator) Provide idealized, rule-agnostic behaviors for UI, analytics, and oracle integrations. They represent the regulatory relationship between base tokens and enforced logic.
  • Entrypoint Functions: (e.g., transfer, balance_of) Provide near-exact estimates of expected outcomes, reflecting policies, rounding, or NAV changes, without executing state updates. These enable accurate transaction planning.
  • Rounding Rules: FA2 mandates rounding in favor of the contract:
    • Round down when issuing tokens or deductions, preventing dilution.
    • Round up when applying policies or requirements, protecting existing participants. These rules ensure fair distribution and discourage precision-based attacks.

FA2 defines three core entry points with batch support, organized by their roles in transfers, queries, and operators. Every contract implements these atomically, ensuring a single source of truth for behavior and movements. Below is the Ligo-equivalent interface, accompanied by developer notes covering edge cases, rounding behavior, and considerations specific to RWA tokens such as asynchronous policies and oracle-driven updates.

1// Ligo (PascaLigo) FA2 Interface
2type token_id = nat;
3type balance = nat;
4type transfer = (address * (address * (token_id * balance)));
5type transfer_list = list(transfer);
6type transfer_param = (address * transfer_list);
7
8type balance_request = (address * token_id);
9type balance_response = ((address * token_id) * balance);
10type balance_callback = list(balance_response);
11
12type operator = (address * address * token_id);
13type operators = list(operator);
14
15type fa2_entry_points =
16  | Transfer of transfer_param
17  | Balance_of of (list(balance_request) * contract(balance_callback))
18  | Update_operators of operators;
19
20// Example Policy: Default (owner or operator)
21type transfer_destination = (address * (token_id * balance));
22type transfer_params = (address * list(transfer_destination));
23
24// Views (TZIP-016)
25type get_balance_param = (address * token_id);
26type get_balance_response = balance;

Detailed Function Breakdown (with RWA Developer Notes)

Below is an entrypoint-by-entrypoint explanation of the FA2 interface, including edge cases, rounding behavior, and RWA-specific implementation guidance for regulated assets, off-chain settlement, and policy-driven validation.

Transfer

Batch list of transfers from source to destinations, each with to, token_id, amount. In RWA tokens, this pins the multi-asset flow for tokenized art, USDC wrappers, or credit notes.

  • This is atomic; partial failure reverts all.

Balance_of

Batch queries for (owner, token_id) pairs, returning via callback contract.

  • RWA Integration: For compliance-based assets, tie to oracle-fed ledgers (Chainlink / Pyth).
  • Edge Case: Must handle empty lists or invalid token_ids (error: FA2_TOKEN_UNDEFINED).

Update_operators

Batch add/remove for (owner, operator, token_id) approvals.

  • Formula: Ledger updates via big_map.
  • Usage: UI quoting, risk dashboards.
  • RWA Note: Reflects pure regulatory mapping, does not account for settlement delays or custody fees.

get_balance ()

Returns balance for (owner, token_id).

  • Ensures no precision-based arbitrage.
  • RWA Note: Useful for NAV disclosures in regulated markets.

total_supply ()

Returns supply for token_id.

  • Return 0 for “no supply” on undefined.
  • RWA Note: Enforce supply caps, jurisdiction restrictions, or temporary pauses due to regulatory flags.

all_tokens ()

Lists all token_ids.

  • Discrepancies vs queries reveal multi-asset impact.
  • RWA Note: Useful for quote generation in hybrid vaults or those with evolving classes.

is_operator ()

Checks if operator for (owner, operator, token_id).

  • Requires prior update check.
  • Includes errors for AML (e.g., FA2_NOT_OPERATOR).
  • RWA Note:
    • For illiquid assets (such as real estate and private credit): pair with policy asynchronous resolutions.
    • Trigger oracle checks for sanctions/residency validation.

Reference Implementation

Tezos Agora’s FA2 offers a mature, formally-verifiable foundation for building multi-asset tokens via Ligo or Archetype. The interface integrates with the kernel, providing a clean entrypoint surface for RWA-specific logic. Its design encourages minimal overrides while still supporting custom policy models, metadata big-maps, operator layers, and oracle integration.

Key capabilities include:

  • Inflation Attack Protection: The implementation prevents dilution by enforcing ledger checks and policy invariants. Early minters cannot exploit low-supply corner cases to extract excess value.
  • Rounding Compliance: All transfers use Michelson nat arithmetic for precise, deterministic operations that adhere to FA2 requirements of rounding in favor of the contract. This eliminates subtle precision-drift exploits.
  • Extensible Policies: Lifecycle entrypoints such as transfer allow developers to embed RWA-specific functionality, NAV oracle checks, compliance gating, settlement status validation, or fee accounting, without modifying core logic.
  • Flexible Structure: FA2 builds on Tezos’ kernel, with optional governance or access controls for regulated administration. This makes it straightforward to integrate custodial controls, upgrade pathways, or policy-gated operations required in regulated RWA environments.
1// Ligo Implementation Snippet (PascaLigo)
2type storage = {
3  ledger : big_map((address, nat), nat);
4  operators : big_map((address, address, nat), unit);
5  token_metadata : big_map(nat, (string * nat)); // TZIP-016
6  policy : (transfer_policy); // Custom for RWA
7};
8
9type transfer_policy =
10  | Owner_transfer
11  | No_transfer
12  | Operator_transfer;
13
14let transfer_policy_check = fun (p : transfer_policy) (src : address) (tx : transfer_destination) (storage : storage) : unit =
15  match p with
16  | Owner_transfer -> unit
17  | No_transfer -> failwith "FA2_TRANSFER_NOT_ALLOWED"
18  | Operator_transfer ->
19    if not (Big_map.mem (src, tx.0, tx.1.0) storage.operators) then
20      failwith "FA2_NOT_OPERATOR"
21    else unit;
22
23let transfer = fun (p : transfer_params) (s : storage) : (list(operation) * storage) =
24  let src = p.0 in
25  let txs = p.1 in
26  let policy_check = transfer_policy_check s.policy src in
27  let update_ledger = fun (tx : transfer_destination) (l : big_map((address, nat), nat)) : big_map((address, nat), nat) =
28    let key_from = (src, tx.1.0) in
29    let bal_from = match Big_map.find_opt key_from l with Some b -> b | None -> 0n in
30    let key_to = (tx.0, tx.1.0) in
31    let bal_to = match Big_map.find_opt key_to l with Some b -> b | None -> 0n in
32    if bal_from < tx.1.1 then failwith "FA2_INSUFFICIENT_BALANCE" else
33    let new_bal_from = bal_from - tx.1.1 in
34    let new_bal_to = bal_to + tx.1.1 in
35    let l' = Big_map.remove key_from l in
36    let l'' = if new_bal_from = 0n then l' else Big_map.add key_from new_bal_from l' in
37    Big_map.add key_to new_bal_to l''
38  in
39  let new_ledger = List.fold (fun (acc, tx) -> update_ledger tx acc) txs s.ledger in
40  ([] : list(operation), { s with ledger = new_ledger });
41
42// Balance_of with callback
43let balance_of = fun (requests : list(balance_request)) (cb : contract(balance_callback)) (s : storage) : (list(operation) * storage) =
44  let responses = List.map (fun (req : balance_request) ->
45    let bal = match Big_map.find_opt (req.0, req.1) s.ledger with Some b -> b | None -> 0n in
46    ((req.0, req.1), bal)
47  ) requests in
48  let op = transaction(responses, 0tez, cb) in
49  ([op], s);
  • The transfer pins policy at storage. For RWA tokens, prefer custom policies and link metadata to IPFS for provenance.
  • Ledger can be extended for NFT mode in UIs.

Transfer Flow (User-Facing)

User-level entrypoints call core logic with policies.

1// As above in transfer()
2// Pre-transfer: Policy check via oracle CPI if needed
  • Use atomic batches for safe multi-txns.
  • Override pre-transfer to add compliance checks (KYC, caps) and revert early if policy fails.
  • For illiquid or async-backed assets, combine transfer with provisional mints and oracle finalization to avoid over-issuance.

Balance_of Flow

Symmetric to transfer, queries return via callback.

1// As in balance_of()
2// Pre-query: Auth via operator if policy-gated
  • Callback-first follows checks-effects-interactions and ensures verifiability.
  • For queued queries, implement off-chain indexer for status.
  • Add query limits via contract storage.

Update_operators Flow

Default updates are owner-gated; RWA overrides query scopes.

1let update_operators = fun (ops : operators) (s : storage) : (list(operation) * storage) =
2  let apply_op = fun (op : operator) (acc : big_map((address, address, nat), unit)) : big_map((address, address, nat), unit) =
3    match op with
4    | (owner, operator, token_id) -> // Add or remove logic
5      Big_map.add (owner, operator, token_id) unit acc // Simplified
6  in
7  let new_ops = List.fold apply_op ops s.operators in
8  ([] : list(operation), { s with operators = new_ops });
  • Update uses big_map for precision.
  • Consider a time-bound policy for approvals.

Adding Custom Policy (Example: Operator-Only)

Policy handling keeps execution consistent.

1// As in transfer_policy_check()
2// For RWA: Integrate oracle for dynamic gating
  • Keep policy accounting transparent: Emit events via callbacks and track via explorer.
  • For RWA products, policies may address regulatory events, document in TZIP-016 metadata.
Stellar Assets Native Issuance Protocol
Tezos CMTAT

WE SECURE EVERYTHING YOU BUILD.

From day-zero risk mapping to exchange-ready audits — QuillAudits helps projects grow with confidence. Smart contracts, dApps, infrastructure, compliance — secured end-to-end.

DeFi SecurityplumeUniswap FoundationAethiropt-collectivePolygon SPNBNB Chain Kickstart

Office 104/105 Level 1, Emaar Square, Building 4 Sheikh Mohammed Bin Rashid Boulevard Downtown Dubai, United Arab Emirates P.O box: 416654

[email protected]

All Rights Reserved. © 2026. QuillAudits - LLC

Privacy Policy