Standardized Assets, Tokens, And Nonfungibles
Discussion regarding standardized assets, tokens, and nonfungibles should take place here.
As the various ERC asset standards, as well as TZIP A1.x have demonstrated, there is a need for standardized assets, tokens, and nonfungibles.
These standards typically center around a standardized interface, such that it's possible to write contracts that can interact with arbitrary tokens that implement the standard.
Existing standards are not decidable, in that it is not possible to algorithmically determine conformity to a standard. It is possible to check for a particular interface, but by Rice's theorem, it cannot be determined that an arbitrary contract implements the semantics for each element of a standard interface correctly.
This presents a major problem for contracts that are intended to handle arbitrary tokens. As a motivating example, consider an exchange contract that makes use of a standard interface for assets in order to facilitate trades, and thus transfers. Should a particular token's contract implement the transfer operation incorrectly, a user may have the unpleasant experience of not receiving tokens that they have paid for, through no fault of their own. Worse, a contract might implement the transfer operation correctly relative to a standard that facilitates permissioned transfers, in which case a user might find themselves able to deposit tokens with an exchange but not able to purchase them (or withdraw them!)
Developers of contracts intended to handle arbitrary tokens are thus forced to whitelist tokens that are accepted to conform to a particular standard. In practice, conformity of tokens to a standard is often determined via informal methods.
Existing standards also suffer from a lack of modularity; Each contract must independently implement the standard. This presents a great obstacle to reasoning about properties of contracts concerned with arbitrary tokens. It would be desirable to have a single contract that handles standard operations, if at all possible.
As a starting point, consider a single contract, with a minimal description: The contract has as it's storage
big_map (address:issuing_contract)
(big_map (bytes:token_id)
(big_map (address:owner)
(nat:amount)))
This structure is interpreted as a ledger whereby each contract may issue a variety of tokens with distinct identifiers, and for each token, the balance of each address is stored.
The contract has the following entrypoints:
issue address (nat: amount) (bytes:token_id)
send address (nat: amount) (pair (address: issuing_contract) (bytes: token_id): full_token_id)
issue address amount token_id
issues amount
of the sender's tokens with identifier token_id
to address
.
send address amount full_token_id
transfers from the sender to address
, amount
of the sender's tokens with the full identifier (issuing contract plus token identifier) full_token_id
.
This single contract would be fully capable of handling the vast majority of existing tokens, even with such a minimalistic description and function.
Note that these operations facilitate operations such as destroying tokens, by sending to an arbitrary burn address, although it may be preferable to implement a destroy operation also.