diff --git a/tips/TIP-0044/tip-0044.md b/tips/TIP-0044/tip-0044.md new file mode 100644 index 000000000..8b256c457 --- /dev/null +++ b/tips/TIP-0044/tip-0044.md @@ -0,0 +1,610 @@ +--- +tip: 44 +title: Foundry Output Type +description: Layer 1 Native Token Foundries +author: + Philipp Gackstatter (@PhilippGackstatter) , Levente Pap (@lzpap) , + Roman Overko (@roman1e2f5p8s) +discussions-to: TODO +status: Draft +type: Standards +layer: Core +created: 2023-05-03 +requires: TIP-21, TIP-22, TIP-45 and TIP-47 +replaces: TIP-18 +--- + +# Summary + +This document defines the Foundry output type and transaction validation rules for the IOTA protocol to support +user-defined layer 1 native tokens. The output defines the supply of such tokens. It was originally introduced in TIP-18 +and the functionality defined in this document is an exact copy of the Foundry output of TIP-18. + +## Summary of changes compared to TIP-18 + +- Remove `Native Tokens` field and add `Native Token Feature` to allowed features. See + [TIP-38 (Native Token Migration)](../TIP-0038/tip-0038.md#native-token-migration) for migration details. + +# Motivation + +The aim of this TIP is to define a Foundry output type to support seamless interoperability between layer 1 and layer 2 +tokenization concepts. The foundry can define the supply of native tokens on layer 1, which can be minted, melted and +transferred with zero fees. + +# Building Blocks + +## Data Types & Subschema Notation + +Data types and subschemas used throughout this TIP are defined in [TIP-21](../TIP-0021/tip-0021.md). + +## Protocol Parameters + +Protocol parameters used throughout this TIP are defined in [TIP-49](../TIP-0049/tip-0049.md). + +## Transaction Payload + +[TIP-45](../TIP-0045/tip-0045.md) is the basis for output validation in this TIP. + +# Immutable Account Address Unlock Condition + +An unlock condition defined for chain constrained UTXOs that can only be unlocked by a permanent Account Address. + +Output unlocking is functionally equivalent to an Address Unlock Condition with an Account Address, +however there are additional transition constraints: the next state of the UTXO machine must have the same Immutable +Account Address Unlock Condition. + +
+ Immutable Account Address Unlock Condition +
Defines the permanent Account Address that owns this output.
+
+ + + + + + + + + + + + + + + +
+ Name + + Type + + Description +
Unlock Condition Typeuint8Set to value 6 to denote an Immutable Account Address Unlock Condition.
Address oneOf +
+ Account Address +
An Address derived from an Account ID which can be unlocked by unlocking the corresponding Account. Defined in TIP-38 (Account Address).
+ + + + + + + + + + + + + + + + +
+ Name + + Type + + Description +
Address Typeuint8Set to value 8 to denote an Account Address.
Account IDByteArray[32]The raw bytes of the Account ID which is the BLAKE2b-256 hash of the Output ID that created it.
+
+
+ +### Additional semantic transaction validation rules: + +- The output must be unlocked with an [_Account Unlock_](#account-unlock-semantic-validation). +- The next state of the UTXO state machine must have the same Immutable Account Address Unlock Condition defined. + +# Foundry Output + +A foundry output is an output that **controls the supply of user defined native tokens.** It can mint and melt tokens +according to the **policy** defined in the `Token Scheme` field of the output. Foundries can only be created and +controlled by accounts. + +**The concatenation of `Address` || `Serial Number` || `Token Scheme Type` fields defines the unique identifier of the +foundry, the `Foundry ID`.** + +Upon creation of the foundry, the account defined in the `Address` field of the Immutable Account Address Unlock +Condition must be unlocked in the same transaction, and its `Foundry Counter` field must increment. This incremented +value defines `Serial Number`, while the `Token Scheme` can be chosen freely. + +`Foundry ID` is not allowed to change after deployment, therefore neither `Address`, nor `Serial Number` or +`Token Scheme` can change during the lifetime of the foundry. + +Foundries control the supply of tokens with unique identifiers, so-called `Token IDs`. The `Token ID` of tokens +controlled by a specific foundry is the same as the `Foundry ID`. + +
+ Foundry Output +
Describes a foundry output that is controlled by an account.
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Name + + Type + + Description +
Output Typeuint8Set to value 3 to denote a Foundry Output.
Amountuint64The amount of IOTA coins held by the output.
Serial Numberuint32The serial number of the foundry with respect to the controlling account.
Token Scheme oneOf +
+ Simple Token Scheme +
A Token Scheme which allows for minting and melting Native Tokens up to the maximum supply.
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Name + + Type + + Description +
Token Scheme Typeuint8Set to value 0 to denote a Simple Token Scheme.
Minted Tokensuint256Amount of tokens minted by this foundry.
Melted Tokensuint256Amount of tokens melted by this foundry.
Maximum Supplyuint256Maximum supply of tokens controlled by this foundry.
+
+
Unlock Conditions Countuint8The number of unlock conditions following.
Unlock Conditions atMostOneOfEach +
+ Immutable Account Address Unlock Condition +
Defines the permanent Account Address that owns this output. Defined in TIP-44 (Immutable Account Address Unlock Condition).
+ + + + + + + + + + + + + + + +
+ Name + + Type + + Description +
Unlock Condition Typeuint8Set to value 6 to denote an Immutable Account Address Unlock Condition.
Address oneOf +
+ Account Address +
An Address derived from an Account ID which can be unlocked by unlocking the corresponding Account. Defined in TIP-38 (Account Address).
+ + + + + + + + + + + + + + + + +
+ Name + + Type + + Description +
Address Typeuint8Set to value 8 to denote an Account Address.
Account IDByteArray[32]The raw bytes of the Account ID which is the BLAKE2b-256 hash of the Output ID that created it.
+
+
+
+
Features Countuint8The number of features following.
Features atMostOneOfEach +
+ Metadata Feature +
Defines a map of key-value pairs that is stored in the output. Defined in TIP-38 (Metadata Feature).
+ + + + + + + + + + + + + + + + + + + + +
+ Name + + Type + + Description +
Feature Typeuint8Set to value 2 to denote a Metadata Feature.
Entries Countuint8The number of entries in the map.
Entries anyOf +
+ Metadata Entry +
A map entry consisting of a string key and an arbitrary byte value.
+ + + + + + + + + + + + + + + + +
+ Name + + Type + + Description +
Key(uint8)ByteArrayA string which may only consist of printable ASCII characters. A leading uint8 denotes its length.
Value(uint16)ByteArrayAn array of arbitrary binary data. A leading uint16 denotes its length.
+
+
+
+
+ Native Token Feature +
A feature that carries a user-defined Native Token minted by a Foundry Output. Defined in TIP-38 (Native Token Feature).
+ + + + + + + + + + + + + + + + + + + + + +
+ Name + + Type + + Description +
Feature Typeuint8Set to value 5 to denote a Native Token Feature.
Token IDByteArray[38]Identifier of the native token. Its derivation is defined in TIP-44 (Foundry Output).
Amountuint256Amount of native tokens of the given Token ID.
+
+
Immutable Features Countuint8The number of immutable features following. Immutable features are defined upon deployment of the UTXO state machine and are not allowed to change in any future state transition.
Immutable Features atMostOneOfEach +
+ Metadata Feature +
Defines a map of key-value pairs that is stored in the output. Defined in TIP-38 (Metadata Feature).
+ + + + + + + + + + + + + + + + + + + + +
+ Name + + Type + + Description +
Feature Typeuint8Set to value 2 to denote a Metadata Feature.
Entries Countuint8The number of entries in the map.
Entries anyOf +
+ Metadata Entry +
A map entry consisting of a string key and an arbitrary byte value.
+ + + + + + + + + + + + + + + + +
+ Name + + Type + + Description +
Key(uint8)ByteArrayA string which may only consist of printable ASCII characters. A leading uint8 denotes its length.
Value(uint16)ByteArrayAn array of arbitrary binary data. A leading uint16 denotes its length.
+
+
+
+
+ +## Additional Transaction Syntactic Validation Rules + +### Output Syntactic Validation + +- It must hold true that `Unlock Conditions Count` = `1`. +- `Unlock Condition Type` of an Unlock Condition must define one of the following types: + - Immutable Account Address Unlock Condition +- Syntactic validation of all present unlock conditions must pass. +- It must hold true that `0` ≤ `Features Count` ≤ `2`. +- `Feature Type` of a Feature in `Features` must define one of the following types: + - Metadata Feature + - Native Token Feature +- It must hold true that `0` ≤ `Immutable Features Count` ≤ `1`. +- `Feature Type` of a Feature in `Immutable Features` must define one of the following types: + - Metadata Feature +- If a _Native Token Feature_ is present in `Features`, its `Token ID` must match the `Foundry ID` of the foundry in + which it is contained. +- Syntactic validation of all present features must pass. +- `Token Scheme` must define one of the following types: + - Simple Token Scheme + +#### Simple Token Scheme Syntactic Validation + +- `Token Scheme Type` of a Simple Token Scheme must be `0`. +- `Minted Tokens` - `Melted Tokens` must not be greater than `Maximum Supply`. +- `Melted Tokens` must not be greater than `Minted Tokens`. +- `Maximum Supply` must be larger than zero. + +## Additional Transaction Semantic Validation Rules + +A foundry is essentially a UTXO state machine. A transaction might either create a new foundry with a unique +`Foundry ID`, transition an already existing foundry or destroy it. The current and next states of the state machine are +encoded in inputs and outputs respectively. + +- The **current state of the foundry** with `Foundry ID` `X` in a transaction is defined as the consumed foundry output + where `Foundry ID` = `X`. +- The **next state of the foundry** with `Foundry ID` `X` in a transaction is defined as the created foundry output + where `Foundry ID` = `X`. +- `Foundry Diff` is the pair of the **current and next state** of the foundry output in the transaction. + +| A transaction that... | Current State | Next State | +| ----------------------- | ----------------------- | ------------------------ | +| Creates the foundry | Empty | Output with `Foundry ID` | +| Transitions the foundry | Input with `Foundry ID` | Output with `Foundry ID` | +| Destroys the foundry | Input with `Foundry ID` | Empty | + +- The foundry output must be unlocked like any other output type where the **Immutable Account Address Unlock + Condition** defines an **Account Address**, by transitioning the account in the very same transaction. See + [TIP-42 (Account Locking & Unlocking)](../TIP-0042/tip-0042.md#account-locking--unlocking) for more details. +- When the current state of the foundry with `Foundry ID` is empty, it must hold true for `Serial Number` in the next + state, that: + - `Foundry Counter(InputAccount) < Serial Number <= Foundry Counter(OutputAccount)` + - An account can create several new foundries in one transaction. It was written for the account output that freshly + created foundry outputs must be sorted in the list of outputs based on their `Serial Number`. No duplicates are + allowed. + - The two previous rules make sure that each foundry output produced by an account has a unique `Serial Number`, hence + each `Foundry ID` is unique. +- Native tokens present in a transaction are all native tokens present in inputs and outputs of the transaction. Native + tokens of a transaction must be a set based on their `Token ID`. +- There must be at most one `Token ID` in the native token set of the transaction that maps to a specific `Foundry ID`. +- When neither `Current State` nor `Next State` is empty: + - Immutable Account Address Unlock Condition must not change. + - `Serial Number` must not change. + - `Token Scheme Type` must not change. + - Features in `Immutable Features` must not change. +- [Token Scheme Semantic Validation Rules](#token-scheme-semantic-validation-rules) must be fulfilled. +- When the Next State is empty, the transaction is invalid if the _Can Destroy Foundry Outputs_ flag in the _Transaction + Capabilities_ is **unset**. + +### Token Scheme Semantic Validation Rules + +`Token Scheme Validation` takes `Token Diff` and `Foundry Diff` and validates if the scheme constraints are respected. + +#### Simple Token Scheme Validation Rules + +- Let `Token Diff` denote the **difference between native token balances of the input and the output side** of the + transaction of the single `Token ID` that maps to the `Foundry ID`. Minting results in excess of tokens on the output + side (positive diff), melting results in excess on the input side (negative diff). Now, the following conditions must + hold for `Token Diff`: + 1. When `Token Diff` > 0 + - `Current State(Minted Tokens) + Token Diff = Next State(Minted Tokens)`. + - `Current State(Melted Tokens) = Next State(Melted Tokens)` + 2. When `Token Diff` < 0, it must hold true that: + - `Current State(Melted Tokens) <= Next State(Melted Tokens)` + - `[Next State(Melted Tokens) - Current State(Melted Tokens)] == |Token Diff|`. + - When `Current State(Melted Tokens) != Next State(Melted Tokens)`, it must be true that + `Current State(Minted Tokens) = Next State(Minted Tokens)` + 3. When `Current State` is empty, `Current State(Minted Tokens) = 0` and `Current State(Melted Tokens) = 0`. + 4. When `Next State` is empty, condition `1` and `2` are ignored. It must hold true, that + `Current State(Minted Tokens) + Token Diff = Current State(Melted Tokens)` +- When neither `Current State` nor `Next State` is empty: + - `Maximum Supply` field must not change. + +## Notes + +- A token scheme is a list of hard coded constraints. It is not feasible at the moment to foresee the future + needs/requirements of hard coded constraints, so it is impossible to design token schemes as any possible combination + of those constraints. A better design would be to have a list of possible constraints (and their related fields) from + which the user can choose. The chosen combination should still be encoded as a bitmask inside the `Token ID`. +- Additional token schemes will be defined that make use of the `Foundry Diff` as well, for example validating that a + certain amount of tokens can only be minted/melted after a certain date. +- For now, only token scheme `0` is supported. Additional token schemes will be designed iteratively when the need + arises. +- The `Foundry ID` of a foundry output should be queryable in indexers, so that given a `Foundry ID`, the `Output ID` of + the foundry output can be retrieved. `Foundry ID` behaves like an address that can't unlock anything. While it is not + necessarily needed for the protocol, it is needed for client side operations, such as: + - Retrieving the current state of the foundry. + - Accessing token metadata in foundry based on `Foundry ID`/`Token ID`. + +# Test Vectors + +The protocol parameters used in the following test vectors are the same as in +[TIP-49 (Protocol Parameters Hash)](../TIP-0049/tip-0049.md#protocol-parameters-hash). + +## Storage Score + +The following test vector shows the calculation of the storage score according to [TIP-47](../TIP-0047/tip-0047.md). + +Foundry Output (json-encoded): + +```json +{ + "type": 3, + "amount": "420000000", + "serialNumber": 1, + "tokenScheme": { + "type": 0, + "mintedTokens": "0x9c40", + "meltedTokens": "0x2710", + "maximumSupply": "0xc350" + }, + "unlockConditions": [ + { + "type": 6, + "address": { + "type": 8, + "accountId": "0x17432c5a7a672503480241125e3952414a7a320441080c624c264b004e09614a" + } + } + ], + "features": [ + { + "type": 2, + "entries": { + "iota": "0x322e3030303030303030303030303030303030303030303030303030303030303030303030303030303030303030" + } + }, + { + "type": 5, + "id": "0x0817432c5a7a672503480241125e3952414a7a320441080c624c264b004e09614a0100000000", + "amount": "0xa410" + } + ] +} +``` + +Foundry Output (hex-encoded binary serialization): + +``` +0x0300b10819000000000100000000409c000000000000000000000000000000000000000000000000000000000000102700000000000000000000000000000000000000000000000000000000000050c300000000000000000000000000000000000000000000000000000000000001060817432c5a7a672503480241125e3952414a7a320441080c624c264b004e09614a02020104696f74612e00322e3030303030303030303030303030303030303030303030303030303030303030303030303030303030303030050817432c5a7a672503480241125e3952414a7a320441080c624c264b004e09614a010000000010a400000000000000000000000000000000000000000000000000000000000000 +``` + +Foundry Output Storage Score: `361`. + +# Copyright + +Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/).