Developer guide to Chrysalis

This is a quick guide meant to help you navigate through some of the differences you will encounter while migrating from IOTA 1.0 to IOTA 1.5, also known as Chrysalis.

Seed and addresses

In Chrysalis, all ternary conversions apart from PoW have been removed which results in a better, faster developer experience. Additionally, the WOTS-Signature has been replaced by a Ed25519 signature scheme. This means that you can now use an address multiple times to send and receive coins.

With these changes, and the further adoption of industry standards, both seeds and addresses will look completely different in IOTA Chrysalis.

IOTA 1.0 address:

UDYXTZBE9GZGPM9SSQV9LTZNDLJIZMPUVVXYXFYVBLIEUHLSEWFTKZZLXYRHHWVQV9MNNX9KZC9D9UZWZRGJMIGPDW

IOTA 1.5 (Chrysalis) address (bech32 standard):

Mainnet with iota

iota1qpw6k49dedaxrt854rau02talgfshgt0jlm5w8x9nk5ts6f5x5m759nh2ml

Testnet with atoi

atoi1qpw6k49dedaxrt854rau02talgfshgt0jlm5w8x9nk5ts6f5x5m75zaxtpj

IOTA 1.5 address anatomy

The IOTA address is based on the Ed25519 signature scheme and it is usually represented by the Bech32 (checksummed base32) format string of 64 characters or hex format:

iota1qpw6k49dedaxrt854rau02talgfshgt0jlm5w8x9nk5ts6f5x5m759nh2ml
three distinguished parts
human-readable id
separator
data
checksum
iota | atoi
1
48 bytes [0..9a..z]
6 characters [0..9a..z]
iota
1
qpw6k49dedaxrt854rau02talgfshgt0jlm5w8x9nk5ts6f5x5m75
9nh2ml
iota = mainnet; atoi = testnet

More information: Protocol-rfc#0020 - Bech32 Address Format

Seed

With the new wallet library, developers do not need to use a self-generated seed anymore. By default, the seed is created and stored in Stronghold, our in-house built security enclave. It is not possible to extract the seed from Stronghold for security purposes. Stronghold uses encrypted snapshots that can easily be backed up and securely shared between devices. These snapshots are then further secured with a password.

More information about IOTA Wallet Library is available on Wallet docs page or in the Exchange guide, which is mainly focused on value transactions.

Please note, it is highly recommended to NOT use online seed generators at all. The seed is the only key to the given funds.

A root of the Ed25519 signature scheme is basically a 32-byte (256-bit) uniformly randomly generated seed based on which all private keys and corresponding addresses are generated. A seed may be represented by a string of 64 characters using [0-9a-f] alphabet (32 bytes encoded in hexadecimal).

The seed can be, for example, generated using the SHA256 algorithm on some random input generated by cryptographically secure pseudo-random generator, such as os.urandom().

Seed examples (a single seed per line):

4892e2265c45734d07f220294b1697244a8ab5beb38ba9a7d57aeebf36b6e84a
37c4aab22a5883595dbc77907c1626c1be39d104df39c5d5708423c0286aea89
e94346bce41402155ef120e2525fad2d0bf30b10a89e4b93fd8471df1e6a0981
...

In modern wallet implementations, such as our wallet.rs library and firefly wallet, the seed is usually generated from a seed mnemonic (seed phrase), using BIP39 standard, to be better memorized/stored by humans. It is based on randomly generated list of english words and is later used to generate the seed. Either way, the seed is a root for all generated private keys and addresses

More information: Protocol-rfc#0010 - Mnemonic Seed

Address/key space

As mentioned above, IOTA 1.5 embraced some existing industry standards, which is obvious even during an address generation process. This includes the BIP32 standard that describes an approach to Hierarchical Deterministic Wallets. The standard was improved by BIP44 recently.

These standards define a tree structure as a base for address and key space generation which is represented by a derivation path:

m / purpose / coin_type / account / change / address_index
  • m: a master node (seed)
  • purpose: constant which is {44}
  • coin_type: a constant set for each crypto currency. IOTA = 4218, for instance.
  • account: account index. Zero-based increasing int. This level splits the address/key space into independent branches (ex. user identities) which each has own set of addresses/keys
  • change: change index which is {0, 1}, also known as wallet chain.
    There are two independent chain of addresses/keys. 0 is reserved for public addresses (for coin receival) and 1 is reserved for internal (also known as change) addresses to which a transaction change is returned. In comparison to IOTA 1.0, IOTA 1.5 is fine with address reuse, and so it is, technically speaking, valid to return transaction change to the same originating address. It is up to developers whether to leverage it or not. iota.rs library and its sibling wallet.rs help with either scenario.
  • address_index: address index. Zero-based increasing int that indicates an address index

As outlined, there is a large address/key space that is secured by a single seed.

And there are few additional things to note:

  • Each level defines a completely different subtree (subspace) of addresses/keys and those are never mixed up
  • The hierarchy is ready to "absorb" addresses/keys for different coins at the same time (coin_type) and all those coins are secured by the same seed
  • There may be also other purposes in the future. However, let's consider a single purpose as of now. The constant 44 stands for BIP44.
  • The standard was agreed upon different crypto communities, although not all derivation path components are always in active use. For example, account is not always actively leveraged across crypto space (if this is a case then there is usually account=0 used)
  • Using different accounts may be useful to split addresses/key into some independent spaces and it is up to developers to implement.

Please note, having many different accounts may have a negative impact on performance while account discovery phase. So, if you are after using multiple, different accounts then you may be interested in our stateful library wallet.rs that incorporates all business logic needed to efficiently manage independent accounts. Additionally, our exchange guide provides some useful tips how different accounts may be leveraged.

address_generation

So in case of IOTA 1.5 (Chrysalis), the derivation path of address/key space is [seed]/44/4218/{int}/{0,1}/{int}:

  • The levels purpose and coin_type are given
  • The rest levels are up to developers to integrate, specifically seed, account, wallet_chain and address_index

More information: Protocol-rfc#0003 - Signature Scheme

Messages, payloads, and transactions

In comparison to original the IOTA 1.0, IOTA 1.5 also introduced some fundamental changes to the underlying data structures. The original concept of transactions and bundles is gone, and has been replaced by a concept of messages and payloads.

A message is a data structure that is actually being broadcast in the IOTA 1.5 network and represents a node (vertex) in the Tangle graph.

It refers to at least 2 and up to 8 previous messages and once a message is attached to the Tangle and approved by a milestone, the Tangle structure ensures the content of the message is unaltered. Every message is referenced by a message_id which is based on a hash algorithm (Blake2b256) of binary content of the message. It also includes previous Tangle messages as its parents which means it is not possible to alter the given message without altering previous messages in the Tangle.

The message is an atomic unit that is confirmed by the network as a whole.

IOTA is no longer based on ternary. IOTA 1.5 uses binary to encode and broadcast all underlying data entities

A message can be up to 32 kb in size and it can hold variable sets of information called payloads. The number of payloads a single message can encapsulate is not given. Even a message without a payload is completely valid and can be broadcast. The Message itself does not include any timestamp; a message timestamp is derived from an acceptance of the given message by the Tangle network.

More information: Protocol-rfc#0017 - Message

Apayload represents a layer of concern. Some payloads may change the state of the ledger (ex. SignedTransactions) and some may provide extra features to some specific applications and business use cases (ex. IndexationPayload).

There are already implemented core payloads, such as SignedTransaction, MilestonePayload, and IndexationPayload but the message and payload definition is generic enough to incorporate any future payload(s) the community agrees upon.

More information: Protocol-rfc#0018 - Transaction Payload

Needless to say, the IOTA network ensures the outer structure of the message itself is valid and strictly complies with network consensus protocol. However, the inner structure is very flexible, future-proof, and offers an unmatched network extensibility.

messages_in_tangle

The current IOTA 1.5 network incorporates the following core payloads:

  • SignedTransaction: a payload that describes UTXO transactions that are the cornerstones of value-based transfers in the IOTA network. Via this payload, a message can be also cryptographically signed
  • MilestonePayload: a payload that is emitted by the Coordinator
  • IndexationPayload: a payload that enables the addition of an index to the encapsulating message, as well as some arbitrary data. The given index can be later used to search the message(s).

In comparison to IOTA 1.0, a message itself is not directly related to the IOTA address while broadcasting to the IOTA 1.5 network. Such messages are referenced using the so-called message_id. Messages are indirectly related to IOTA addresses via SignedTransaction payload, specifically the UTXO section.

Unspent Transaction Output (UTXO)

Originally, IOTA 1.0 used an account-based model for tracking individual iota tokens: each IOTA address held a number of tokens and the aggregated number of tokens from all iota addresses was equal to the total supply.

In contrast, IOTA 1.5 uses the unspent transaction output model, or UTXO. It is based on an idea to track unspent amounts of tokens via a data structure called output.

Below is a simplified analogy of how the UTXO works:

  • There are 100 tokens recorded in the ledger as Output A and this output belongs to Alice. So, the initial state of the ledger: Output A = 100 tokens
  • Alice sends 20 tokens to Paul, 30 tokens to Linda, and keeps 50 tokens at her disposal
  • Her 100 tokens are recorded as Output A so she has to divide (spent) tokens and create three new outputs:
    Output B with 20 tokens that goes to Paul, Output C with 30 tokens that goes to Linda, and finally Output D with the rest of the 50 tokens that she kept for herself
  • Original Output A was completely spent and cannot be used any more. It has been spent and so becomes irrelevant to ledger state.
  • New state of ledger: Output B = 20 tokens, Output C = 30 tokens and Output D = 50 tokens
  • The total supply remains the same, just number of outputs differs and some outputs were replaced by other outputs in the process

utxo

The key takeaway of the outlined process above is the fact that each unique output can be spent only once. Once the given output is spent, it cannot be used any more and is irrelevant in regards to the ledger state.

So even if Alice still wants to keep remaining tokens at her fingertips, those tokens have to be moved to a completely new output that can be, for instance, still tied to the Alice's same iota address as before.

Every output also stores information about an IOTA address to which it is coupled with. So addresses and tokens are indirectly coupled via outputs. Basically, the sum of outputs and their amounts under the given address is a balance of the given address, ie., the number of tokens the given address can spend. And the sum of all unspent outputs and their amounts is equal to the total supply.

Outputs are being broadcasted encapsulated in a message as a part of SignedTransaction payload.

Selected message payloads

Currently, there are two commonly used message payloads, IndexationPayload and SignedTransaction which can be combined based as needed.

More information: Protocol-rfc#0018 - Transaction Payload

IndexationPayload

IndexationPayload is a payload type that can be used to attach an arbitrary data and key index to a message. When this particular payload is leveraged, then a message and related data entity can be searched via key index in addition to a message_id.

SignedTransaction

SignedTransaction is a payload type that is used to transfer value-based messages as UTXO. It changes the ledger state as old outputs are being spent (replaced) and new outputs are being created.

Each SignedTransaction includes the following set of information:

  • inputs - a list of valid outputs that should be used to fund the given transaction. Outputs are uniquely referenced via previous transaction_id and inner index. At least one output has to be given with enough balance to source all outputs of the given message
  • outputs - a list of IOTA address(es) and related amount(s) the input outputs should be split among. Based on this information, new UTXO outputs are being created
  • unlock_blocks - it includes a transaction signature(s) (currently based on Ed25519 scheme) that proves token ownership based on a valid seed

Dust protection

Since IOTA is feeless and has the ability to send microtransactions, attackers could use this to spam the network with very low value transactions, which we call dust. To avoid this, we only allow microtransaction below 1Mi (dust) of IOTA tokens to another address if you already have at least 1Mi as a dust allowance output on that address. The number of allowed dust outputs on an address is the amount of the dust allowance outputs divided by 100,000 and rounded down, i.e. 10 outputs for each 1 Mi deposited, with a maximum of 100 dust outputs in total.

In the UTXO model, each node in the network needs to keep track of all the currently unspent outputs. When the number of outputs becomes too large, it can cause performance and memory issues. The RFC below proposes a new protocol rule regarding the processing of outputs where they transfer a very small amount of IOTA’s so-called dust outputs. Dust outputs are only allowed when they are backed up by a certain deposit on the receiving address. This limits the amount of dust outputs, thus making it expensive to proliferate dust. Since a receiver must make a deposit, the protocol makes receiving dust an opt-in feature.

More information: Protocol-rfc#0032 - Dust Protection

Up to 8 Parents

With IOTA 1.0, you always had to reference 2 parent transactions. With Chrysalis, we introduce a more dynamic number of parent nodes where you can reference up to 8 parents. We recommend you reference at least 2 unique parents at all times for the best possible results.

More information: Protocol-rfc#0017 - Message