Pascal – Non fungible token with FA2 (Operator)

Chapter 29 : FA 2.0 – Operators and Permissions

When we started our space expedition, you chose a ship that was unique, there is no other like it, treat it well!


The FA2 standard proposes a unified token contract interface that accommodates fungibility and multiple asset concerns. It aims to provide significant expressivity to contract developers to create new types of tokens while maintaining a common interface standard for wallet integrators and external developers.

In this chapter we will focus on Operators and Permissions.

Entry points

Token contract implementing the FA2 standard MUST have the following entry points.

type fa2_entry_points is
Transfer of transfer_params
| Balance_of of balance_of_params
| Token_metadata_registry of token_metadata_registry_params
| Permissions_descriptor of permissions_descriptor_params
| Update_operators of update_operator_params
| Is_operator of is_operator_params



An Operator can be seen as a delegate role.

An Operator is a Tezos address that initiates token transfer operation on behalf of the owner. An Owner is a Tezos address which can hold tokens. An operator, other than the owner, MUST be approved to manage particular token types held by the owner to make a transfer from the owner account. The Operator relation is not transitive. If C is an operator of B , and if B is an operator of A, C cannot transfer tokens that are owned by A, on behalf of B.

An operator is defined as a relationship between two address (owner address and operator address) and can be understood as an operator address which can operate tokens held by a owner.

FA2 interface operator

The FA2 interface specifies two entry points to update and inspect operators. Once permitted for the specific token owner, an operator can transfer any tokens belonging to the owner.

| Update_operators of update_operator_params
| Is_operator of is_operator_params

where parameter type update_operator_params and is_operator_params are :

type operator_param_ is record
owner : address
; operator : address

type operator_param is michelson_pair_right_comb(operator_param_)

type update_operator_param is
| Add_operator of operator_param
| Remove_operator of operator_param

type update_operator_params is list (update_operator_param)

type is_operator_response_ is record
operator : operator_param
; is_operator : bool

type is_operator_response is michelson_pair_right_comb(is_operator_response_)

type is_operator_params_ is record
operator : operator_param
; callback : contract (is_operator_response)

type is_operator_params is michelson_pair_right_comb(is_operator_params_)

Notice that the update_operator can only Add or Remove an operator (an allowance between an operator address and a token owner address).

Notice that the parameter is\operator_params given to *Is\operator entry point contains a callback* property used to send back a response to the calling contract.

Notice that the entry point Update_operators expects a list of update_operator_param.

FA2 standard operator library

Some helper functions has been implemented in the FA2 library which help manipulating operator relationship. This library contains following functions and type alias :

an operator is a relationship between two address (owner address and operator address)

function update_operators allows to Add or Remove an operator in the list of operators.

function validate_operator validates operators for all transfers in the batch at once, depending on given operator_transfer_policy

FA2 Permission Policies and Configuration

Most token standards specify the logic that validates a transfer transaction and that can either approve or reject a transfer. Such logic (called Permission Policy) could validate who initiates a transfer, the transfer amount, and who can receive tokens.

This FA2 standard defines a framework to compose and configure such permission policies.

The FA2 standard defines :

  • the default core transfer behavior, that MUST always be implemented
  • a set of predefined permission policies that are optional

Permissions descriptor

The FA2 standard specifies an interface permissionsdescriptor allowing external contracts to discover an FA2 contract’s permission policy and to configure it. *permissions\descriptor* serves as a modular approach to define consistent and non-self-contradictory policies.

The permission descriptor indicates which standard permission policies are implemented by the FA2 contract and can be used by off-chain and on-chain tools to discover the properties of the particular FA2 contract implementation.

The FA2 standard defines a special metadata entry point permission descriptor containing standard permission policies.

type permissions_descriptor_ is record
operator : operator_transfer_policy
; receiver : owner_hook_policy
; sender : owner_hook_policy
; custom : option (custom_permission_policy)


FA2 token contract MUST implement the Permissions_descriptor entry point which provides token policies.

| Permissions_descriptor of permissions_descriptor_params

The expected parameter permissions_descriptor_params for this entry point is a callback function sending back a permissions_descriptor to calling contract. Those calling contract are considered as “Fa2 client contract”.

type permissions_descriptor is michelson_pair_right_comb(permissions_descriptor_)

type permissions_descriptor_params is

  contract (permissions_descriptor)

Operator transfer policy

operator_transfer_policy – defines who can transfer tokens. Tokens can be transferred by the token owner or an operator (some address that is authorized to transfer tokens on behalf of the token owner). A special case is when neither owner nor operator can transfer tokens (can be used for non-transferable tokens).

The FA2 standard defines two entry points to manage and inspect operators associated with the token owner address (update_operators, is_operator). Once an operator is added, it can manage all of its associated owner’s tokens.

type operator_transfer_policy =

  | No_transfer

  | Owner_transfer

  | Owner_or_operator_transfer

Owner hook policy

owner_hook_policy – defines if sender/receiver hooks should be called or not. Each token owner contract MAY implement either an fa2_token_sender or fa2_token_receiver hook interface. Those hooks MAY be called when a transfer sends tokens from the owner account or the owner receives tokens. The hook can either accept a transfer transaction or reject it by failing.

type owner_hook_policy =

  | Owner_no_hook

  | Optional_owner_hook

  | Required_owner_hook

Custom permission policy

It is possible to extend a permission policy with a custom behavior, which does not overlap with already existing standard policies. This standard does not specify exact types for custom config entry points. FA2 token contract clients that support custom config entry points must know their types a priori and/or use a tag hint of custom_permission_policy.

type custom_permission_policy = {

  tag : string;

  config_api: address option;


Permission Policy Formulae

Each concrete implementation of the permission policy can be described by a formula which combines permission behaviors in the following form:

Operator(?) * Receiver(?) * Sender(?)

This formula describes the policy which allows only token owners to transfer their own tokens :

Operator(Owner_transfer) * Receiver(Owner_no_hook) * Sender(Owner_no_hook)

Your mission

We are working on a non_fungible/single-asset token. Our NFT “token” is almost ready but to allow a new rule. We need Bob to transfer a token taken from Vera account and send it to alice’s account.

  • Alice’s account address is “tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN”
  • Bob’s account address is “tz1faswCTDciRzE4oJ9jn2Vm2dvjeyA9fUzU”
  • Vera’s account address is “tz1b7tUupMgCNw2cCLpKTkSD1NZzB5TkP2sv”

1- First we want you to prepare the initial state of storage. Modify the ligo compile-storage command for the token contract with following recommandations :

  • Vera account is owner of the token 1

2- Complete the ligo dry-run command for authorizing Bob to transfer tokens taken from Vera account, transaction emitted by Vera. (reuse the storage you made on step 1). You can use Layout.convert_to_right_comb function to convert your parameters into the format expected by Update_operators entry point. Don’t forget to refer to fa2interface to know the the expected type of *Update\operators* entry point.

3- Complete the ligo dry-run command for simulating the transfer of 1 token from Vera’account to Alice’s account, transaction emitted by Bob. The transferred token id is number 1 (token_id and and amount must be 1). You can use the Layout.convert_to_right_comb function to convert your parameters into the format expected by Transfer entry point.

You will have to modify the storage accordingly:

  • “Vera account is owner of the token 1” (step 1)
  • “Bob is authorized to transfer tokens taken from Vera account” (step 2).
  • Exercise
  • fa2_operator_lib.ligo
  • fa2_interface.ligo
  • non_fungible_token.ligo


Type your solution above and validate your answer