Skip to content

Latest commit

 

History

History
420 lines (297 loc) · 19.1 KB

0.md

File metadata and controls

420 lines (297 loc) · 19.1 KB
FATIP Title Status Category Author Created
0 Fungible Token Standard Draft Token Standard Devon Katz <devonk@dbgrow.com> 7-23-2018

Summary

This document describes the functionality, datastructures, and validation rules of the FAT-0 token standard. FAT-0 is a data-only, fungible token standard built on Factom chains and entries. Its functionality is most alike to the ERC-20 token standard of Ethereum.

Motivation

Create a decentralized, open token standard on top of the Factom protocol. The FAT-0 standard allows issuance and trade tokenized assets between Factoid addresses.

Following the Factom ethos, FAT standards are data-only protocols, and can be implemented on top of any system that supports immutable ordered data, such as Factom.

FAT-0 fills a critical gap between Colored Coins (BTC) and ERC (Ethereum) tokens. Implementation of the FAT-0 standard on Factom results in an immutable, fixed cost token system that is inexpensive to build, issue, and transfer tokens on:

  • $0.012 USD to issue a new FAT-0 token
    • Additional $0.001 USD/KB of optional user defined content up to 10KB
  • $0.001 USD to transact an unlimited number of tokens
    • Additional $0.001 USD/KB of optional user defined content up to 10KB

Because the standard supports arbitrary user defined data, it offers a base for more complex user defined behavior based on the underlying data. Custom token systems may be built on top of the basic functionality of this standard.

Applications include ICOs, digital currencies, digital goods, and accounting.

Specification

Token ID

A human readable string unique to the Issuer's Identity Chain ID. This ID and the Issuer's Identity Chain ID are the only pieces of data needed to retrieve the token's data from Factom. It should be something short and memorable related to your token. For example: mytoken is the token ID of the FAT-0 test token: My Token (MYT).

TODO: Add example issuer id for this example token.

Note that two Issuers could use the same Token ID since the Issuers will have different Identity Chain IDs. It is up to users to decide which Issuer's token they wish to use. Trust in an Issuer is necessary to trust the integrity of future token distribution decisions.

Addresses

FAT-0 uses Factom's Factoid Address key pairs based on ed25519 cryptography to send and receive tokens.

Reserved Coinbase & Burn Address

The public Factoid Address FA1zT4aFpEvcnPqPCigB3fvGu4Q4mTXY22iiuV69DqE1pNhdF2MC, representing the public address corresponding to the Factoid private key with all zeros (Fs1KWJrpLdfucvmYwN2nWrwepLn8ercpMbzXshd1g8zyhKXLVLWj) is a reserved address for minting and burning tokens.

Only coinbase transactions are allowed from this address, which must be signed by the identity of the token issuer. Tokens sent to this address are provably un-spendable (burnt). This address is not allowed to send tokens from its balance under any circumstance.

Token Chain

A Factom chain is used to hold the token issuance and transactions of the token. The Factom Blockchain provides a fixed ordering of transactions and issuances, a requirement for determining consensus around the state of balances and transaction validation.

Token Chain ID extends FATIP-100

The Token Chain ID can be calculated by using the Issuer's Identity Chain ID and the Token ID. The token chain has the following External IDs.

External ID Index External ID Value
0 "token"
1 <Hex Encoded Token ID>
2 "issuer"
3 <Hex Encoded Issuer Identity Root Chain ID>

For example, for FAT-0 token mytoken:

Chain ID = sha256(sha256("token") | sha256("mytoken") | sha256("issuer") | sha256("888888dd9e60c1f0216f753caf5c9b5be4c9ca69db27a6c33d30dce3fe5ee709"))
Chain ID = 0x85ab32f9748bf4c24cedb301bc5a4938eb5cd4a5b0bb46b70027bf983f579a2e

Where sha256d is a double round of sha256 hashing: sha256d(x) = sha256(sha256(x))

Token Issuance Entry extends FATIP-101

A data structure called the Token Issuance holds the information about the FAT-0 token such as it's name, symbol, and supply.

The official issuance entry is the first well-formed entry on the token's token chain that has a valid signature from the Issuer's SK1 key identified by the Issuer's Identity Chain.

There may only be one issuance entry per FAT-0 token. It should be noted that due to the implementation of FATIP-100 in this spec, the signed issuance entry cannot be the first entry in the token chain, since it's ExtIDS must be exact. The issuance entry may occur at any position in the chain. Invalid entries are simply ignored.

From FATIP-101, the data being signed shall be the Chain ID of the token chain concatenated with the entry content. The issuer shall be the hex encoded Issuer Identity Root Chain ID used in chain ID derivation, and the IDKey used shall be the IDKey of issuer at the time of entry to Factom.

Issuance Entry Content Example

{
  "type": "FAT-0",
  "supply": 10000000,
  "name": "Example Token",
  "symbol": "EXT",
  "salt": "874220a808090fb736f345dd5d67ac26eab94c9c9f51b708b05cdc4d42f65aae",
}

Issuance Entry Field Summary & Validation

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 be in circulation Must be greater than 0 if included. Omission means supply is unlimited N
name string The display name of the token none N
symbol string The display symbol of the token must be A-Z, and 1-4 characters in length N
salt string Random string to salt the issuance user defined. Optional N

Issuance Entry External IDs Summary & Validation

External ID Index Type Description Validation Required
0 raw binary data Raw ed25519 signature output of signing issuance chainID + entry content. ed25519 signature validation (chainID+ entry content, idKey, ExtID[0]) Y

Token Transaction Entry extends FATIP-101

Token Transaction Entries represent the signed transfer of an amount of FAT-0 tokens from one Factoid address to another. Anyone who wishes to make a transaction must create a well-formed entry with a valid signature on the token's chain.

The order of transactions is solely determined by the order the transaction entries appear in the token chain. Factom provides a locked, time ordered record of submission for each transaction. The presense of a Transaction Entry in the chain is necessary but not sufficient for the transaction to be considered valid. Sufficient balance, valid signatures, as well as some other requirements to prevent replay attacks are described below.

FAT-0 transactions borrow cryptographic elements from Factoid Transactions, including it's RCD (Redeem Condition Datastructure) address format, and signatures. FAT-0 transactions are multi-input, multi-output (MIMO).

For standard transactions, RCDs and corresponding signatures are provided in the External IDs of the Transaction Entry. For coinbase transactions that initially distribute tokens, the signatures are provided in the structure of the entry as described by FATIP-101.

Transaction ID

The unique ID of a transaction is its entry hash in the Factom blockchain. This is a unique hash of all of the data in the content and the External IDs of the entry.

Transaction Entry Content Example

{
   "inputs:":{
      "FA1zT4aFpEvcnPqPCigB3fvGu4Q4mTXY22iiuV69DqE1pNhdF2MC": 100,
      "FA2y6VYYPR9Y9Vyy1ZuZqWWRXGXLeuvsLWGkDxq3Ed7yc11dbBKV": 50
   },
   "outputs:":{
      "FA3aECpw3gEZ7CMQvRNxEtKBGKAos3922oqYLcHQ9NqXHudC6YBM": 150
   },
   "salt":"80d87a8bd5cf2a3eca9037c2229f3701eed29360caa975531ef5fe476b1b70b5"
}

Transaction Entry JSON Field Summary & Validation

Name Type Description Validation Required
inputs object The inputs of this this transaction Mapping of Public Factoid Address => Input amount. Amount must be a positive nonzero integer (units of of 1^-10 of a token). Must contain at least 1 key-value pair. No duplicate keys. Y
outputs object The outputs of this transaction Mapping of Public Factoid Address => Input amount. Amount must be a positive nonzero integer (units of of 1^-10 of a token). Must contain at least 1 key-value pair. No duplicate keys. Y
salt string Random string to salt the transaction Must be at least 1 character long Y

External IDs

Transaction Entries must include exactly two External IDs for every input address listed in the transaction: the RCD that hashes to the corresponding input address, and a signature.

In the case of normal transaction, all inputs must have a corresponding RCD in an even External ID.

In the case of coinbase transactions, the RCD in the 0th External ID must hash to the ID Key of the issuing Identity as per FATIP-101.

Since the Transaction Entry Hash MUST be unique, implementations must ignore any entries that do not contain EXACTLY twice as many External IDs as inputs. This prevents replay of transactions through manipulating the Transaction Entry Hash by appending additional External IDs to a previously posted valid transaction.

In the following table X is any even number less than 2n.

External ID Index External ID Value (RAW DATA)
0 RCD corresponding to one of the inputs or Issuer ID Key
1 ed25519 signature by key of RCD in preceding External ID
2 RCD corresponding to one of the inputs
3 ed25519 signature by key of RCD in preceding External ID
...
X RCD corresponding to one of the inputs
X + 1 ed25519 signature by key of RCD in preceding External ID
Encoding

All of the RCD and Signature External IDs in a Transaction Entry shall be raw data and not use any encoding. The Factom Explorer now properly displays External IDs that contain raw data as hex encoded data. So there is little reason to encode the data we put in the External IDs.

RCD

The RCD is a data structure that hashes to the payload of a Factoid Address. The RCD data structure is 33 bytes long. The first byte is the RCD type (0x01), the remaining 32 bytes are a ed25519 public key.

Factoid Addresses contain a header and a checksum, which is described futher in the Factom Data Structures Documentation.

To validate that an RCD "corresponds" to a Factoid Address,

  1. Convert the Factoid Address string from base58 to raw bytes.
  2. Remove the first 2 bytes header bytes and the last four bytes checksum bytes.
  3. The remaining 32 bytes must be the double SHA256 hash of the raw bytes of the RCD.
Signature

The cryptographic signature algorithm is the same as that used in a Factoid Transaction.

From the Factom Documentation:

  • Factoids use Ed25519 with Schnorr signatures. They have many benefits over the ECDSA signatures used in Bitcoin.
  • The signatures are enforced to be canonical. This will limit malleability by attackers without the private key.

A signed transaction should only be valid once, so signed data must be protected against replay within a given FAT chain and across various FAT chains. For this reason both the index of the External ID and the chain id is used to salt the signature. This prevents reordering the External IDs and replaying a transaction on a different chain.

Let i be the integer index of the External ID that the signature will be place in the Factom Entry.

The signed data shall be the concatenation of the following:

  1. The shortest (no leading zeros) string decimal representation of int(i/2)
  2. The raw bytes of the chain ID
  3. The content of the entry

For example, if there were two inputs, and + is concatenation of bytes, then the valid External IDs would be,

ExtID[0] = 0x01 + pub_key0
ExtID[1] = ed25519_sign(priv_key0, "0" + chain_id + entry_content)
ExtID[2] = 0x01 + pub_key1
ExtID[3] = ed25519_sign(priv_key1, "1" + chain_id + entry_content)

Transaction Validation and State

There are two types of transactions which have slightly different validation requirements: Normal transactions between Factoid Addresses, and Coinbase transactions that mint tokens. Coinbase transactions require an additional signature of the entry content by the issuer, stored in the transaction's ExtIds.

A Coinbase transaction is identified by whether it has an input from the Coinbase address: FA1zT4aFpEvcnPqPCigB3fvGu4Q4mTXY22iiuV69DqE1pNhdF2MC

Computing the current state

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 and sequentially, updating the state for any transaction that meets all of the necessary Transaction Validation Requirements.

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.

for entry in transaction_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

Transaction Validation Requirements

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.

In general, requirements are ordered by the computational and programmatic ease of checking.

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.x Requirements for all transactions
  • T.1.1: The content of the entry must be a single well-formed JSON.
  • T.1.2: The JSON must contain all required transaction fields listed in the above table. The fields must comply with all stated validation criteria. No unspecified fields may be present.
  • T.1.3: The entry MUST contain exactly 2n External IDs, where n is the number of keys in the inputs object. This is required to prevent replay attacks.
  • T.1.4: A Factoid Address may only appear ONCE in the inputs and outputs objects combined. This means that the "inputs" and "outputs" may not share any common keys (Factoid Addresses), nor each have any duplicates.
  • T.2.1: The sum of all values(amounts) in the inputs object must be equal to the sum of all values(amounts) in the outputs object.
  • T.2.2: The entry hash of the transaction entry must be unique among all transactions belonging to this token.
  • T.3.1: If i is odd then the ith External ID must be the raw data of a valid signature verified against the public key stored in the last 32 bytes of the RCD in the i-1th External ID. The signed message shall be the following three things concatenated in order:
    1. The shortest (no leading "0") decimal string representation of int(i/2)
    2. The raw bytes of the chain id
    3. The raw bytes of the content of the entry

The first prevents replay attacks from reordering External IDs, and the second prevents replay attacks across FAT token chains.

N.x Requirements for normal account-to-account transactions

Normal transactions must meet all T.x and N.x requirements.

All references to External ID indexes use 0-based indexing.

  • N.2.1: The Coinbase address (FA1zT4aFpEvcnPqPCigB3fvGu4Q4mTXY22iiuV69DqE1pNhdF2MC) may not exist as a key in inputs.
  • N.2.2: The Factoid Addresses (keys) in inputs must all have balances greater than or equal to their respective input amounts.
  • N.3.1: For each input address, there exists an External ID with even index which is the raw data of an RCD which hashes to the raw data payload of the human readable Factoid Address input.
C.x Requirements for Coinbase distribution transactions

Coinbase transactions must meet all T.x and C.x requirements.

  • C.1.1: The inputs object may contain only the public coinbase address as a key (FA1zT4aFpEvcnPqPCigB3fvGu4Q4mTXY22iiuV69DqE1pNhdF2MC)
  • C.2.1: The coinbase 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 RCD in the first External ID must hash to the PK1 key of the Token Issuer's Identity Chain.

Implementation

No implementation notes at this time.

Copyright

Copyright and related rights waived via CC0.