diff --git a/tips/TIP-0050/tip-0050.md b/tips/TIP-0050/tip-0050.md new file mode 100644 index 000000000..12b87955a --- /dev/null +++ b/tips/TIP-0050/tip-0050.md @@ -0,0 +1,264 @@ +--- +tip: 50 +title: Configurable Addresses +description: Configurable Address Container to customize what kind of assets can be received +author: + Philipp Gackstatter (@PhilippGackstatter) , Alexander Sporn (@alexsporn) + +discussions-to: TODO +status: Draft +type: Standards +layer: Interface +created: 2023-09-04 +--- + +# Summary + +This document proposes an extension to the address format to make them configurable. This enables an address to opt-in +or -out of certain functionality, like disabling the receipt of Native Tokens, NFT Outputs or Timelock Unlock +Conditions. + +# Motivation + +[TIP-18](../TIP-0018/tip-0018.md) introduced a multi-asset ledger. Every user is able to receive different kinds of +Outputs (Basic, Alias, NFTs) and the ledger has useful functionality like time-based unlock conditions. Not every user +wants to deal with the complexity of this functionality, but users were so far unable to disable them. Certain users do +not want to receive certain asset classes like Native Tokens or Non-Fungible Tokens for legal reasons. Configurable +addresses solve this issue by adding capabilities to addresses. Such addresses self-describe their capabilities which +make it possible to express whether an address can receive such assets. As a result, these address capabilities impose +additional validation rules for transactions in which outputs contain such addresses in their unlock conditions. + +This TIP builds on the address format defined in TIP-11 in a backwards-compatible manner, while extending the +capabilities of the address. + +# Binary serialization + +The format of a restricted address is a container around other address types. A restricted address is serialized in +three parts: + +- The first field describes the type of the address. +- The second field contains another concrete Address type. +- The third field contains bitflags in a variable-size byte array which are the _Allowed Capabilities_. See + [Allowed Capabilities](#allowed-capabilities) for their serialization. + +## Data Types & Subschema Notation + +Data types and subschemas used throughout this TIP are defined in [TIP-21](../TIP-0021/tip-0021.md). + +## Restricted Address + +The following table shows the mapping from the address type of the **first byte** to the address type: + +| Address | Type Byte as `uint8` | Bech32 Encoded | +| ------------------ | -------------------- | -------------- | +| Restricted Address | 48 | iota1**x**... | + +The following table shows the serialization of a _Restricted Address_: + +
+ Restricted Address +
An address that contains another address and allows for configuring its capabilities.
+
+ + + + + + + + + + + + + + + + + + + + +
+ Name + + Type + + Description +
Address Typeuint8Set to value 48 to denote a Restricted Address.
Address oneOf +
+ Ed25519 Address +
An Address derived from an Ed25519 Public Key. Defined in TIP-38 (Ed25519 Address).
+
+
+ Account Address +
An Address derived from an Account ID which can be unlocked by unlocking the corresponding Account. Defined in TIP-38 (Account Address).
+
+
+ NFT Address +
An Address derived from an NFT ID which can be unlocked by unlocking the corresponding NFT. Defined in TIP-38 (NFT Address).
+
+
+ Anchor Address +
An Address derived from an Anchor ID which can be unlocked by unlocking the corresponding Anchor. Defined in TIP-38 (Anchor Address).
+
+
+ Multi Address +
Defines a Multi Address that consists of addresses with weights and a threshold value. The Multi Address can be unlocked if the cumulative weight of all unlocked addresses is equal to or exceeds the threshold. Defined in TIP-52 (Multi Address).
+
+
Allowed Capabilities(uint8)ByteArrayBitflags expressed as a series of bytes. A leading uint8 denotes its length.
+ +### Unlocking + +The address is unlocked in a transaction if and only if the underlying `Address` is unlocked. + +## Allowed Capabilities + +Allowed Capabilities are represented as a `ByteArray` with a length prefix. For the address that contains them to be +valid, the following conditions must hold: + +- The length prefix must be `0`, `1` or `2`. + - This condition may be relaxed in the future and implementations should anticipate greater lengths. +- Bit indices start at `0`. For each byte, they are counted starting from the least-significant bit. If there was a + previous byte, the indices continue where the previous byte's indices left off. + - For example: In this list of two bytes with the bit patterns `0001 0000` and `0000 0100`, bits with indices `4` and + `10` are set. +- There must be no trailing zero bytes in the byte array. + - This rule ensures that an address with the same raw address bytes and the same capabilities will yield the same + binary and bech32 representation. + +### Capability Flags + +The following table shows the mapping from the bit pattern to the capability flags, where the `Flag Index` is the index +of the bit. + +This list is an Allowlist: If the bit is `1` (**set**) the address has the capability, if the bit is `0` (**unset**) it +does not have it. + +| Flag Index | Capability (if flag is set) | +| ---------- | ------------------------------------------------------------------- | +| 0 | Can receive Outputs with Native Tokens. | +| 1 | Can receive Outputs with Mana. | +| 2 | Can receive Outputs with a Timelock Unlock Condition. | +| 3 | Can receive Outputs with an Expiration Unlock Condition. | +| 4 | Can receive Outputs with a Storage Deposit Return Unlock Condition. | +| 5 | Can receive Account Outputs. | +| 6 | Can receive Anchor Outputs. | +| 7 | Can receive NFT Outputs. | +| 8 | Can receive Delegation Outputs. | + +### Syntactic transaction validation rules + +This section defines the transaction validation rules coming into effect with the capability flags. These are defined in +terms of the flags being **unset**. If the flag is **set**, the rule does not apply to the transaction. + +If an output is created on the output side of a transaction with an _Address Unlock Condition_, _State Controller +Address Unlock Condition_, _Governor Address Unlock Condition_ or _Expiration Unlock Condition_ containing a _Restricted +Address_, the transaction is only valid if the following conditions, corresponding to the _Allowed Capabilities_ flags, +hold for that output: + +- Flag 0 **unset**: The transaction is invalid if the output's `Native Tokens Count != 0`. +- Flag 1 **unset**: The transaction is invalid if the output's `Mana != 0`. +- Flag 2 **unset**: The transaction is invalid if the output contains an unlock condition of type Timelock Unlock + Condition. +- Flag 3 **unset**: The transaction is invalid if the output contains an unlock condition of type Expiration Unlock + Condition. +- Flag 4 **unset**: The transaction is invalid if the output contains an unlock condition of type Storage Deposit Return + Unlock Condition. +- Flag 5 **unset**: The transaction is invalid if the output is an Account Output. +- Flag 6 **unset**: The transaction is invalid if the output is an Anchor Output. +- Flag 7 **unset**: The transaction is invalid if the output is an NFT Output. +- Flag 8 **unset**: The transaction is invalid if the output is an Delegation Output. + +## Examples + +### Allowed Capabilities Bit Patterns + +The following shows examples of Allowed Capabilities bit patterns and their meaning. This only shows the first two bytes +of the Allowed Capabilities array. + +| Bit Pattern | Meaning | +| ------------------- | -------------------------------------------------------- | +| 0000 0011 0000 0000 | Can receive Native Tokens and Mana. | +| 1110 0000 0000 0001 | Can receive Account, Anchor, NFT and Delegation Outputs. | +| 0000 1100 0000 0000 | Can receive Outputs with time-based unlock conditions. | + +### Bech32 Strings + +The following examples show regular addresses and examples for when they are wrapped by a _Restricted Address_ with +various capabilities. + +- **Ed25519 Address (Plain)** + - Hex-encoded binary serialization (33 bytes): `0x00efdc112efe262b304bcf379b26c31bad029f616ee3ec4aa6345a366e4c9e43a3` + - Bech32 string: `iota1qrhacyfwlcnzkvzteumekfkrrwks98mpdm37cj4xx3drvmjvnep6xqgyzyx` +- **Restricted Ed25519 Address (Every Capability Disallowed)** + - Hex-encoded binary serialization (35 bytes): + `0x3000efdc112efe262b304bcf379b26c31bad029f616ee3ec4aa6345a366e4c9e43a300` + - Bech32 string: `iota1xqqwlhq39mlzv2esf08n0xexcvd66q5lv9hw8mz25c695dnwfj0y8gcq8mnjgf` +- **Restricted Ed25519 Address (Every Capability Allowed)** + - Hex-encoded binary serialization (37 bytes): + `0x3000efdc112efe262b304bcf379b26c31bad029f616ee3ec4aa6345a366e4c9e43a302ff01` + - Bech32 string: `iota1xqqwlhq39mlzv2esf08n0xexcvd66q5lv9hw8mz25c695dnwfj0y8gczluqs97eene` +- **Restricted Ed25519 Address (Can receive Native Tokens)** + - Hex-encoded binary serialization (36 bytes): + `0x3000efdc112efe262b304bcf379b26c31bad029f616ee3ec4aa6345a366e4c9e43a30101` + - Bech32 string: `iota1xqqwlhq39mlzv2esf08n0xexcvd66q5lv9hw8mz25c695dnwfj0y8gcpqyla70tq` +- **Account Address (Plain)** + - Hex-encoded binary serialization (33 bytes): `0x0860441c013b400f402c317833366f48730610296a09243636343e7b1b7e115409` + - Bech32 string: `iota1ppsyg8qp8dqq7spvx9urxdn0fpesvypfdgyjgd3kxsl8kxm7z92qj2lln86` +- **Restricted Account Address (Every Capability Disallowed)** + - Hex-encoded binary serialization (35 bytes): + `0x300860441c013b400f402c317833366f48730610296a09243636343e7b1b7e11540900` + - Bech32 string: `iota1xqyxq3quqya5qr6q9schsvekday8xpss994qjfpkxc6ru7cm0cg4gzgq9nu0d0` +- **Restricted Account Address (Every Capability Allowed)** + - Hex-encoded binary serialization (37 bytes): + `0x300860441c013b400f402c317833366f48730610296a09243636343e7b1b7e11540902ff01` + - Bech32 string: `iota1xqyxq3quqya5qr6q9schsvekday8xpss994qjfpkxc6ru7cm0cg4gzgzluqs9xmye3` +- **Restricted Account Address (Can receive Native Tokens)** + - Hex-encoded binary serialization (36 bytes): + `0x300860441c013b400f402c317833366f48730610296a09243636343e7b1b7e1154090101` + - Bech32 string: `iota1xqyxq3quqya5qr6q9schsvekday8xpss994qjfpkxc6ru7cm0cg4gzgpqys8pcr3` +- **NFT Address (Plain)** + - Hex-encoded binary serialization (33 bytes): `0x10140f39267a343f0d650a751250445e40600d133522085d210a2b5f3f69445139` + - Bech32 string: `iota1zq2q7wfx0g6r7rt9pf63y5zyteqxqrgnx53qshfppg4470mfg3gnjfmvts0` +- **Restricted NFT Address (Every Capability Disallowed)** + - Hex-encoded binary serialization (35 bytes): + `0x3010140f39267a343f0d650a751250445e40600d133522085d210a2b5f3f6944513900` + - Bech32 string: `iota1xqgpgreeyearg0cdv5982yjsg30yqcqdzv6jyzzayy9zkheld9z9zwgqjt4fkk` +- **Restricted NFT Address (Every Capability Allowed)** + - Hex-encoded binary serialization (37 bytes): + `0x3010140f39267a343f0d650a751250445e40600d133522085d210a2b5f3f6944513902ff01` + - Bech32 string: `iota1xqgpgreeyearg0cdv5982yjsg30yqcqdzv6jyzzayy9zkheld9z9zwgzluqs3ctnc5` +- **Restricted NFT Address (Can receive Native Tokens)** + - Hex-encoded binary serialization (36 bytes): + `0x3010140f39267a343f0d650a751250445e40600d133522085d210a2b5f3f694451390101` + - Bech32 string: `iota1xqgpgreeyearg0cdv5982yjsg30yqcqdzv6jyzzayy9zkheld9z9zwgpqysq5lyk` + +# Rationale & Alternatives + +- The default capability byte should be `0x00` as `0` is a sensible default value, and results in the desired + configuration since adding new flags in the future would mean that addresses automatically opt-out of that capability, + until they explicitly set the flag to `1`. That is the reason why the flags are defined as an Allow List rather than a + Deny List. A `0x00` byte as the default disallows every available capability for restricted address types. +- An alternative would be to reuse the current address type byte as both a type indicator and for capability flags. This + makes serialization less straightforward as there could be many bit patterns that identify a given address type. + Separating the address type and capabilities separates serialization and capability setting & extraction, which are + two different concerns. +- Another alternative would be to have two versions of each address type: An unrestricted one and a restricted one. The + former would allow every capability implicitly, and the latter - in contrast - disallows everything by default. This + would result in a proliferation of address types which is undesirable. +- Backwards-compatibility with the existing address format is important since addresses are highly user-facing and users + expect them to be stable and permanent. Thus, adding a new configurable version of addresses means + backwards-compatibility with previous address types as they are not replaced, while also allowing for configurable + versions of each address to be created. +- The rules for restricted addresses do not apply to the _Return Address_ of a _Storage Deposit Return Unlock Condition_ + (SDRUC) because the requirements towards outputs in such a return transaction are already as restricted as a fully + restricted address, as defined in [TIP-38](../TIP-0038/tip-0038.md#storage-deposit-return-unlock-condition). +- For unlocking, the Restricted Address must be resolved to its underlying address. This is because it is only a + container around another address type and is not a standalone identity itself. With this approach, users can add + restrictions on existing addresses, but it continues to act as if it was the underlying address for Unlocks in a + transaction or in Sender and Issuer Features. + +# Copyright + +Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/).