FATIP | Title | Status | Category | Author | Created |
---|---|---|---|---|---|
0 | Fungible Token Standard | Accepted | Token Standard | Devon Katz <[email protected]> | 7-23-2018 |
This document describes the functionality, data structures, and validation rules of the FAT-0 token standard. FAT-0 is a fungible token standard. Its functionality is most alike the ERC-20 token standard of Ethereum.
Fungible tokens are ubiquitous in the cryptocurrency space. The properties of fungible tokens are generally what most people expect from a currency: units of the token are interchangeable and indistinguishable. Most currencies and assets have this property, thus it follows that the first basic FAT token type should be a simple fungible token.
- Specification
- Implementation
- Copyright
A single Factom chain is used to hold the initialization of the token and all subsequent transaction. The Factom Blockchain provides the underlying consensus mechanism for the content and ordering of transactions. Clients shall apply transactions in the order that they appear in the Factom Token Chain.
The Token Chain ID is calculated by using the Token ID and the Issuer's Identity Chain ID as described in FATIP-100.
As the purpose of the first entry in the Token Chain is solely intended to create a chain with the appropriate Name IDs, the content of the first entry in a Token Chain is ignored.
Factom Chains are permissionless, meaning that anyone can pay to submit any entry on any chain. Thus implementations must parse all entries and determine their validity.
All valid entries must adhere to the following.
Only entries submitted on the Token Chain may be valid. Thus all entries must be properly submitted and paid for according to Factom's rules. Implementations shall not prematurely apply pending Factom entries to the token state.
In order to ensure consistency across implementations, all JSON must be parsed very strictly. In addition to the JSON structure being well-formed with all required fields present, the following are strictly prohibited:
- unknown fields
- fields with unexpected types
- duplicate field names
Note that duplicate field names are not strictly prohibited by the JSON specification. Parsing duplicate field names may differ by implementation. See Implementation Notes for some mechanisms to detect and prohibit duplicate field names if the JSON library does not support their detection natively.
All valid entries must have External IDs with valid signatures that conform to the specifications defined by FATIP-103. The required set of signatures depends on the entry and is defined below for each entry type.
The Token Initialization Entry establishes parameters and metadata about the Token. All entries prior to the first valid Initialization Entry shall be ignored. A Token may only be initialized once and these parameters and metadata cannot ever be modified. Subsequent Initializations entries after the first valid one, are always considered invalid and ignored.
{
"type": "FAT-0",
"supply": 10000000,
"precision": 5,
"symbol": "EXT",
"metadata": {"custom-field": "example"}
}
Name | Type | Description | Validation | Required |
---|---|---|---|---|
type |
string | The type of this token issuance. | Must equal 'FAT-0'. | Y |
supply |
number | The maximum possible number of tokens that can ever be issued. | Must be greater than 0, or -1 for an unlimited supply. All other values are invalid. | Y |
precision |
number | The decimal accuracy of the tokens base unit (e.g. each 1 EXT is composed of 10 ^ 5 base units). | Must be an integer in the range 0-18 inclusive. Default 0. | N |
symbol |
string | The display symbol of the token. | Must be A-Z, and 1-4 characters in length. | N |
metadata |
any | Optional metadata defined by the Issuer. | This may be any valid JSON type. | N |
The Initialization Entry must be signed by the Issuer's key established by the Identity Chain referenced in the Token Chain's Name IDs. Thus the Identity Chain must exist and be properly set up with a key at the time that the Initialization Entry is submitted. See FATIP-101 for details on key selection from the Identity Chain and FATIP-103 for details on signing and External IDs.
Token Transaction Entries represent the transfer of an amount of FAT-0 tokens from one Factoid address to another. Anyone who wishes to make a transaction must publish a valid Transaction entry to the Token Chain. There are two types of Transactions: Normal transactions created by the holders of the Token and Coinbase Transactions created by the Issuer.
The unique ID of a transaction is its Factom entry hash. The Transaction ID is a hash of all of the entry data including the content and the External IDs. Entries possessing the same Transaction IDs are duplicates and so are ignored to prevent replay attacks.
{
"inputs:": {
"FA1zT4aFpEvcnPqPCigB3fvGu4Q4mTXY22iiuV69DqE1pNhdF2MC": 100,
"FA2y6VYYPR9Y9Vyy1ZuZqWWRXGXLeuvsLWGkDxq3Ed7yc11dbBKV": 50
},
"outputs:": {
"FA3aECpw3gEZ7CMQvRNxEtKBGKAos3922oqYLcHQ9NqXHudC6YBM": 150
},
"metadata": {"memo": "thanks for dinner!"}
}
Name | Type | Description | Validation | Required |
---|---|---|---|---|
inputs |
object | The inputs of the transaction | Mapping of Public Factoid Address => Amount. Amount must be am integer greater than or equal to zero. May not be empty or contain duplicate Addresses. | Y |
outputs |
object | The outputs of the transaction | Mapping of Public Factoid Address => Amount. Amount must be am integer greater than or equal to zero. May not be empty or contain duplicate Addresses. May overlap with addresses found in inputs to form a send-to-self transaction. Sum of the Amounts must equal the sum of the inputs Amounts. |
Y |
metadata |
any | Optional metadata defined by user | This may be any valid JSON type. | N |
For a Transaction to be well-formed it must follow the above defined structure with all required fields. Additionally, the token amounts must be conserved. In other words the sum of the inputs must be exactly equal to the sum of the outputs. Finally duplicate addresses within a Transaction are prohibited. This includes duplicate addresses within the inputs or outputs as well as duplicate addresses between the inputs or outputs. Thus tokens may not be sent from an address to itself within the same transaction. This reduces the complexity of implementations.
Transactions are signed according to FATIP-103. The signing set is
the set of keys corresponding to the addresses in the inputs. A transaction
must include an RCD/Signature pair for each input in the transaction. The order
of the addresses in the inputs
field does not matter, so the RCD/Signature
pairs may appear in the External IDs in any order, so long as the signatures
are properly salted with their External ID position, as specified in FATIP-103.
FAT-0 uses Factom's Factoid Address RCD key pairs based on ed25519 cryptography to send and receive tokens.
The public Factoid Address
FA1zT4aFpEvcnPqPCigB3fvGu4Q4mTXY22iiuV69DqE1pNhdF2MC
, corresponding to the
Factoid private key with all zeros
(Fs1KWJrpLdfucvmYwN2nWrwepLn8ercpMbzXshd1g8zyhKXLVLWj
) is a reserved address
used for two purposes: issuing and burning tokens.
Any tokens sent to the Coinbase address are forever burned and irrecoverable, even by the Issuer of the token.
Only Coinbase Transactions may use the Coinbase address as an input. Coinbase Transactions issue and distribute new tokens to other addresses. To clarify, tokens sent from this address are not previously burned tokens, but new tokens adding to the circulating supply.
Coinbase Transactions are special Transaction Entries generated by the Token Issuer that issue new tokens to addresses. Coinbase Transactions may not increase the total supply (circulating and burned) beyond the maximum supply declared in the Initialization Entry.
Coinbase Transactions follow the same structure as normal transactions
described above, but with the Coinbase Address as the sole input in the
inputs
object. Coinbase Transactions may not include any other address in the
inputs
object.
A signature from the current key establised by the Issuer's Identity key is required. See FATIP-101 and FATIP-103.
All Transactions must meet all of the T.x requirements.
Normal Transactions must additionally meet all of the N.x requirements.
Coinbase Transactions must additionally meet all of the C.x requirements.
The x.1.x requirements are generally data structure validations.
The x.2.x requirements are generally parsing and other content validations.
The x.3.x requirements are generally related to cryptographic validations.
- T.1.1: The content of the entry must be a single well-formed JSON.
- T.1.2: The JSON must contain all required fields listed in the above table, all fields and their members must be of the correct type. No unspecified fields may be present. No duplicate field names are allowed.
- T.1.3: A Factoid Address key may only appear once in each of the
inputs
andoutputs
objects. This means that theinputs
andoutputs
may not have any duplicate keys, respectively. - T.2.1: The sum of all amounts in the
inputs
object must be equal to the sum of all amounts in theoutputs
object. - T.2.2: The entry hash of the transaction entry must be unique among all previously valid transactions belonging to this token.
- T.3.1: The External IDs must follow the cryptographic and structural requirements defined by FATIP-103.
Normal transactions must meet all T.x and N.x requirements.
- N.2.1: The Coinbase address may not be an input.
- N.2.2: The balances of the input addresses must all be greater than or equal to their respective amounts declared in the transaction.
- N.3.1: For each input address, there exists a corresponding valid RCD/Signature pair in the External IDs as specified by FATIP-103. No additional RCD/Signature pairs beyond those that correspond with an input may be included.
Coinbase transactions must meet all T.x and C.x requirements.
- C.1.1: The Coinbase address must be the only input.
- C.2.1: The input amount plus the sum of tokens issued in all previous
Coinbase transactions must be less than or equal to
supply
from the Issuance entry (if not unlimited). - C.3.1: The entry must be signed by the Issuer's currently established key in the Identity chain according to FATIP-101 and FATIP-103.
Implementations must maintain the state of the balances of all addresses in order to evaluate the validity of a transaction. The current state can be built by iterating through all entries in the token chain in chronological order and updating the state for any valid transaction.
The following pseudo code describes how to compute the current state of all balances. A transaction must be applied entirely or not at all. Entries that are not valid transactions are simply ignored. Transactions must be evaluated in the order that they appear in the token chain. This assumes the token has already been properly initialized.
for entry in token_chain.entries:
if entry.is_valid_transaction():
if !entry.is_coinbase_transaction():
for input in entry.inputs:
balances[input.address] -= input.amount
for output in entry.outputs:
balances[output.address] += output.amount
- FAT Daemon & CLI (fatd) - Official FAT token daemon, API server, and CLI implementation
- A program written in Go that tracks and validates FAT Token chains, and provides up an API for other applications to access FAT's data.
- fat-js - Official FAT Javascript library for NodeJS & Browser
- FAT Wallet - Official FAT Wallet UI
Most JSON libraries do not consider duplicate field names to be an error. Thus
they can go undetected if not mitigated through other detection mechanisms. One
simple way to detect duplicate field names is to compare the length of the
minified JSON with the expected length of the JSON after parsing all of the
fields. The expected length is easy to determine once all of the fields are
parsed. See the fatd
reference implementation of fat0.Transaction
or
fat0.Initialization
for examples of this.
A less efficient way to detect this is to parse the JSON, then regenerate the JSON and compare the lengths of the JSON with the minified original.
In both cases it is necessary to minify the JSON since users may add any valid whitespace to their JSON.
Copyright and related rights waived via CC0.