Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TIP-50: Configurable Addresses #151

Draft
wants to merge 43 commits into
base: main
Choose a base branch
from
Draft
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
cfbe787
Adapt TIP-47 from TIP-19
PhilippGackstatter May 12, 2023
4f67068
Merge pull request #12 from iotaledger/tip47
muXxer May 12, 2023
54d3faa
Replace TIP-19, add TIP-47 in Readme
PhilippGackstatter May 16, 2023
4b8ecf8
Fix concept typo
PhilippGackstatter Aug 14, 2023
f7c714b
Add initial TIP-50 document
PhilippGackstatter Sep 5, 2023
6193225
Add rational & alternative
PhilippGackstatter Sep 5, 2023
26cc013
Adapt title and summary to clarify changes
PhilippGackstatter Sep 5, 2023
b870dfb
Fix bytes/bits typo
PhilippGackstatter Sep 5, 2023
4bb10e9
Update address type & capability byte approach
PhilippGackstatter Sep 6, 2023
c565ff2
Add missing type bit
PhilippGackstatter Sep 6, 2023
045d83d
Remove Account/NFT Address with capabilities
PhilippGackstatter Sep 6, 2023
fdaec55
Add address type -> bech32 character info
PhilippGackstatter Sep 6, 2023
65dc9a8
Adapt to address & capabilities separation
PhilippGackstatter Sep 6, 2023
6bf9938
Update drawbacks, rationale, examples
PhilippGackstatter Sep 7, 2023
10a77e8
Polish TIP
PhilippGackstatter Sep 8, 2023
6c836fd
Capitalize `Outputs`
PhilippGackstatter Sep 8, 2023
8a15771
Remove dash in `xx-bytes`
PhilippGackstatter Sep 8, 2023
c052a26
Apply suggestions from code review
PhilippGackstatter Sep 8, 2023
d1aa345
Clarify bit indices counting
PhilippGackstatter Sep 8, 2023
1e78708
Apply suggestions from code review
PhilippGackstatter Sep 13, 2023
3c19c5e
Clarify capability summary
PhilippGackstatter Sep 13, 2023
9e05253
Improve capability type description
PhilippGackstatter Sep 13, 2023
5fbacf8
Added unified restricted address type and examples
muXxer Sep 21, 2023
8fbe4cb
Make TIP specific to restricted addresses
PhilippGackstatter Sep 26, 2023
d766315
Remove Bech 32 encoding duplication with TIP 11
PhilippGackstatter Sep 26, 2023
ae1704b
Add note on serialization table
PhilippGackstatter Sep 26, 2023
21fc627
Fix sparsity typo
PhilippGackstatter Sep 26, 2023
e96f0ff
Update rationales
PhilippGackstatter Sep 26, 2023
9eedbb7
Fix indentation of semantic tx rules
PhilippGackstatter Oct 2, 2023
3994af9
Add unlocking section
PhilippGackstatter Oct 4, 2023
e5f426a
Update Restricted Address schema
PhilippGackstatter Oct 4, 2023
6c02425
Add authors
PhilippGackstatter Oct 16, 2023
11711ef
Remove outdated TIP-47
PhilippGackstatter Oct 17, 2023
4174339
Revert changes to README and TIP-19
PhilippGackstatter Oct 17, 2023
8143114
Merge pull request #21 from iotaledger/chore/replace-tip19
PhilippGackstatter Oct 17, 2023
49f5dc9
Remove manually added Table of Contents
PhilippGackstatter Oct 24, 2023
014c0e4
Update description & format markdown
PhilippGackstatter Oct 24, 2023
8092444
Merge remote-tracking branch 'tips-draft/main' into tip50
PhilippGackstatter Oct 24, 2023
d5e6216
Add Anchor capability & update Bech32 examples
PhilippGackstatter Oct 26, 2023
39ae200
Update Restricted Address type value
PhilippGackstatter Nov 3, 2023
d157cc8
Add Anchor Address in Restricted Address
PhilippGackstatter Nov 3, 2023
85393d0
Make transaction validation rules syntactic
PhilippGackstatter Nov 7, 2023
30646c7
Add no trailing zero bytes rule
PhilippGackstatter Nov 8, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
264 changes: 264 additions & 0 deletions tips/TIP-0050/tip-0050.md
Original file line number Diff line number Diff line change
@@ -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) <[email protected]>, Alexander Sporn (@alexsporn)
<[email protected]>
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_:

<details>
<summary>Restricted Address</summary>
<blockquote>An address that contains another address and allows for configuring its capabilities.</blockquote>
</details>
<table>
<tr>
<td>
<b>Name</b>
</td>
<td>
<b>Type</b>
</td>
<td>
<b>Description</b>
</td>
</tr>
<tr>
<td>Address Type</td>
<td>uint8</td>
<td>Set to <strong>value 48</strong> to denote a <i>Restricted Address</i>.</td>
</tr>
<tr>
<td valign="top">Address <code>oneOf</code></td>
<td colspan="2">
<details>
<summary>Ed25519 Address</summary>
<blockquote>An Address derived from an Ed25519 Public Key. Defined in <a href='../TIP-0038/tip-0038.md#ed25519-address'>TIP-38 (Ed25519 Address)</a>.</blockquote>
</details>
<details>
<summary>Account Address</summary>
<blockquote>An Address derived from an Account ID which can be unlocked by unlocking the corresponding Account. Defined in <a href='../TIP-0038/tip-0038.md#account-address'>TIP-38 (Account Address)</a>.</blockquote>
</details>
<details>
<summary>NFT Address</summary>
<blockquote>An Address derived from an NFT ID which can be unlocked by unlocking the corresponding NFT. Defined in <a href='../TIP-0038/tip-0038.md#nft-address'>TIP-38 (NFT Address)</a>.</blockquote>
</details>
<details>
<summary>Anchor Address</summary>
<blockquote>An Address derived from an Anchor ID which can be unlocked by unlocking the corresponding Anchor. Defined in <a href='../TIP-0038/tip-0038.md#anchor-address'>TIP-38 (Anchor Address)</a>.</blockquote>
</details>
<details>
<summary>Multi Address</summary>
<blockquote>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 <a href='../TIP-0052/tip-0052.md#multi-address'>TIP-52 (Multi Address)</a>.</blockquote>
</details>
</td>
</tr>
<tr>
<td>Allowed Capabilities</td>
<td>(uint8)ByteArray</td>
<td>Bitflags expressed as a series of bytes. A leading <code>uint8</code> denotes its length.</td>
</tr>
</table>

### 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/).
Loading