FA2.1 / FA3 - It's time

Hello guys,
I’m joining the discussion late. There are some interesting points raised here.

A point that has not been addressed yet is the deprecation of FA1.2?. A quick look over the standard leads to believe that FA1.2 is for FT and FA2 is for NFT, leading dev to create new FA1.2 token which I think is bad. People should use exclusively FA2. However some people prefer the FA1.2 due to the possibility to delegate only part of their stack to an operator while in FA2, we always delegate all of our stacks.

To avoid people using FA1.2 we may want to add this in a future FA2.1.

The other point is that the callback entrypoint should be replaced with views. Interacting with “Michelson view entrypoints” or “callback entrypoint” leads to potential vulnerability due to reentrance issues and exposure of an entrypont for the callback, that could be call by an implicit account.
For this reason, I believe that we want to upgrade FA2 quickly before any other discussion about a new standard. Just for people to stop using this.
This would be FA2.1. There may be some compatibility issues between FA2.1 and FA2 due to this last change. Then we may want to call it FA3 to signal this.

However, I want this change to be integrated quickly and I belive everybody would agree that using views instead of callback is a better design. And I also agree that we want a new standard with the other mentioned functionalty. Thus if we call this token FA3, I believe views won’t be integrated quickly because the community will discuss about the integration on these new functionality.

To sum up, I lack experience to have a clear opinion on weither such token should be FA2.1 or FA3, as their is pros and cons with both naming. Your opinion on this would be appreciated.

1 Like

Major issue for wallets at the minute is lack of standardisation around metadata. Wallet users want to do all kinds of searching, sorting, grouping, filtering etc of tokens and NFT’s. But to this day the main indexers still don’t have a means of even saying if a token is an NFT or not. Wallets have to relying on hacky code and exception lists, while indexers are putting hardcoded data into their databases to manually “fix” such issues. This is not sustainable and causes a lot of delays in certain projects becoming fully supported.

With multiple “types” of tokens now possible, we need a standardised way to denote what they are (e.g. “token”, “liquidity token”, “nft”).

We need standardised ways to name different things. Have a look at any ETH wallet, you will see NFT’s grouped into sections like “Rarible” with a raribale company logo next to it, that users can expand. These are all hardcoded in tezos apps because theres no easy way to fetch these things. Sometimes you will get lucky and find a project that does expose these things, but it can’t be relied on unless everyone does it.

When discussing standards, the top priority needs to be talking to the major indexers and the major wallets to see what they and their users need. Making a new standard/features is meaningless unless it can be integrated in the way users want to use it

3 Likes

You right @simonmcl . The goal of standardization is to make it easy for wallet and dex to access any token and get metadata on them. We should have it accessible on the contract. I am thinking we need a place for constant on a Michelson contract. To identify data easily but also have the guarantee that they won’t be overwritten

1 Like

I upvote it. It’s great. When will we submit a new FA standard? I think it’s time to do it. The fake on-chain view on FA2 is not acceptable. We need improve it now.

1 Like

I dont know the current status about a new Token standard. If it is actually work in progress or nothing yet just talk on Agora? @veqtor started this thread maybe he knows more

Please don’t ruin FAs with all this bloat. You all are not looking for new “FA” standards but for new NFT-supporting TZIPs. Which is fine. Put them in TZIPs, another “FA” will be a huge pain in the ass for current and future Tezos developers.

Having to support both FA1.2 and FA2 is already a pain. Adding another or even FA2.1 will be worse. FA2 is fine for simple tokens as it is, FA1.2 is essentially rekt imo and shouldn’t be used, but new apps still choose it because of loose and unclear messaging from top devs.

What you really want is new TZIP standards. Look at Uniswap for example, they still exclusively deal with simple ERC-20s. As a DEX developer, I agree and will likely never support any “financial assets” past FA2 unless I really have to. Financial assets should be as simple as possible to allow for more complex interaction in base layer protocols.

We should be pushing modular TZIPs that can be optionally implemented to extend FA2. Not FA2.1, not FA3, not FA++, or God-FA.

And reaaally what yall are looking for is field-level standardization for token_metadata. That’s what everyone is already set up to read, and how the wallet or exchange knows to load the token image, name, symbol, etc. We have first-class support for it. So why not just make what we have better via TZIP? Tezos needs a core, base-layer FA that doesn’t get remade every 2 years.

Tokens do not need to do everything, developers should be shrewd enough to actually design their tokens well and choose what TZIPs to implement instead of relying on copying whatever boilerplate FA is posted in OpenMinter’s github. Heavy amounts of hand-holding will lead to this conversation happening again and again whenever a new protocol-level feature comes out.

As I see it, FA2s do everything necessary to allow simple token transfers, exchanges, management, and metadata storing. My request is that we keep standards clear of optional features.

This has been stated multiple times in this very thread, and folks need to accept it to move this conversation forward.

3 Likes

I can agree to most things but like @KStasi wrote in the Madfish Blogpost, support of views should be introduced. I dont know if possible but keep current issued FA1.2 and FA2 tokens but introduce a FA3 standard and with the introduction mark the others or at least FA1.2 as deprecated to use?

Is there actually some development ongoing for FA3 besides this discussion here?

Hello!

There’s not much I’d really want from an FA2.1/3. Here’s a short list:

  • allowances (for fungible multi-tokens)
  • relaxing the constraints on storage layouts (to allow for some more storage efficient token contracts)
  • clearly defined onchain views, ideally compatible with the FA2 offchain views so no one who just went that route gets retconned.
2 Likes

Unfortunately there is no standard way to separate nfts from fungible tokens right now when I make api calls to get all token. The only way to distinguish them is to use some heuristics, but they won’t be 100% accurate. I think something on token standard level to clearly separate this two would help many

1 Like

Another thing I’d love to see us do better than ethereum on FA3:

On chain royalty definition from the get-go in BPS. Required to define the entrypoint/storage in some way, with a standard value for “no royalties”. Have them respected by the transfer function when XTZ amount is non-zero in the tx.

Currently royalties are stored entirely off chain, forcing web3 front ends do most of the heavy lifting of fetching metadata files, parsing the royalty config, and then feeding it into their contracts. This puts way too much pressure on the web3 developer to calculate royalties and adjust their contract code to match. Every token should be queryable for it’s royalty configuration in BPS standard. Pass in token and return a list of records containing address and BPS value. Otherwise we are certainly going to see platforms pop up which completely circumnavigate around royalties like we do on Eth since it isn’t on chain nor apart of the transfer standard (https://sudoswap.xyz).

2 Likes

Just wanted to throw my two cents in here as someone who has now dropped two collectible PFP projects on Tezos as well as written an FA2 trading contract:

  • FA3 needs to extend the FA2 standard for backwards compatibility. We should only add and modify existing implementations, not change existing method stubs. Many of our “off chain” standards should and can move to first class.
  • Balance_of is very weirdly designed. You cannot get the return value in the same entrypoint it was called in, which kind of defeats the utility of it. You have to call it in a separate pre-tx and then batch together multiple of your own contract calls after that (now that storage is set). Is there no way to solve this? Can we not make this easier for devs?
  • The is a bug in the operators standard that will cause the same type of hacks we’ve seen plague OpenSea. When you transfer the token to someone, then you get the token back, your operators are still set to what they were when you first owned the token. This is unexpected and can allow old (compromised) contracts which were allowed safe to operate years ago to still have operation now when the user is returned the token. Operators should be zerod out upon transfer. We can learn from this mistake in the ERC721 standard on Eth.
  • It’s very odd to me that the update_operators function is first class but then the boolean is_operator is optional? There is no good way to check if something has approval rights to a token right now within one entrypoint. is_operator should be moved to first class required.
  • I’ve noticed that the only way to check if someone owns a token reliably is to for the user to transfer it to the contract, and then have the contract transfer it right back in the same entrypoint. Since this workaround already works but is gassy, we may as well standardize a less gassy way of getting the same information. Moving a few of these “off-chain” optional calls to first class required would solve this. At the very least we should make self-sending a feature, so we can halve the number of calls here and avoid the ledger updating on the FA2 contract for nothing.
4 Likes

Now that we have events in Tezos (blog post), I would suggest adding standardized events to FA2.1/3, similar to ERC-777 and ERC-721. I think such events would help off-chain apps such as indexers observe state changes of the token contracts reliably.

I imagine their types would look something like this in CameLIGO (the exact definitions can change)

type balance_update_event = { owner : address; token_id : nat; diff : int; }
type operator_update_event = { owner : address; operator : address; token_id : nat; is_operator : bool }

And will be emitted like this:

EMIT %tzipXX_balance_update [{ owner =...; token_id=...; diff=...}; ...]
EMIT %tzipXX_update_operator [{ owner =...; operator=...; token_id=...; is_operator=...}; ...]

Here are the Michelson types of the above events for reference:

(list %balance_update_events
  (pair
    (address %owner)
    (pair
      (nat %token_id)
      (int %diff)
    )
  )
)

(list %operator_update_events
  (pair
    (address %owner)
    (pair
      (address %operator)
      (nat %token_id)
      (bool %is_operator)
    )
  )
)

We can also add the updated balance in the balance_update_event like this:

(list %balance_update_events
  (pair
    (address %owner)
    (pair
      (nat %token_id)
      (int %diff)
      (nat %updated_balance)
    )
  )
)

Having balance in the event would enable Merkle proofs of the current balance, and I imagine it would be convenient for other usage too.

2 Likes

I suggested the %updated_balance and the Merkle proofs, but I am very unsure about it.

It seems generally convenient, maybe, but it increases the complexity. One example: what should a consumer believe if the %diff and %updated_balance are inconsistent? Another example: a tuple of three integer values (Pair 42 42 42) is at least three times more confusing than a tuple of two integer values.

The Merkle proofs with %updated_balance seem significantly less powerful than what we already (kind of) have without events …if you let yourself look at contract storage in the context.

A third alternative would be to have only the %updated_balance without the %diff. Which of these alternatives is best?

Interesting. What should happen for tokens with balance > 1? The operator state should be cleared when the balance reaches 0? Or upon any individual transfer?

It was designed with a callback because FA2 came before onchain events were developed.
It would be better to replace this endpoint by a view in future standard.

I saw some token contracts already using a view so Indexers may already manage both

We have worked on a first draft for the specification of the FA2 update: FA2.1 - HackMD

The goal of the FA2.1 extension is to include new protocol features while remaining fully compatible with current applications that rely on the FA2 standard.

Events are a means to solve discoverability problems encountered by indexers, i.e. to know when a token is transferred especially outside the specified transfer entrypoint (mint, burn, etc…).

On-chain views are a means for smart contracts to share information easily. Callback views are kept for compatibility with already deployed contracts.

Tickets are a way to materialize tokens outside of smart contracts. They can be transferred without calling the creator contract and affecting its status. Tezos rollups rely on tickets for representing Layer 1 assets on Layer 2.

Additionally, finite allowance, enabling a user to grant permission to spend a fixed amount of tokens, is introduced (based on the FA1.2 scheme).

4 Likes

I read the draft and parts of this thread.

Some thoughts as a DeFi developer:

  • I want a simple standard that uses events and on chain views
  • I don’t want to think about FA2 style callback views
  • approve is fine, operators are probably less fine, but mainly I just don’t want to deal with both at the same time
  • I think optional backwards compatibility is way less useful (therefore no harm in dropping it completely)
  • I don’t see why the ticket related code needs to be in the token contract
  • I think the modularity mentioned by @arrijabba is a good goal, but I don’t like using FA2 as the base
1 Like

The ticket holds the address of the contract that created it so it’s easy to check if the ticket is valid or not. An alternative would be to have a ticket wrapper that everyone agrees on