In depth explanation of how IOTA making a transaction

Original Post –
All Credits to Louie Lu

This post will in-depth in-detailed to explain how IOTA making a transaction, from transaction to bundle, from hash to address, from private key to signature message. This is all you need about to know how IOTA proposed a transaction from one address to another.

blog post:

0. Before We Start

Please make sure you have already read this two material:

  1. Bundles — IOTA Documentations
  2. Making a Transaction — IOTA Documentations

It gives you the basic view of IOTA transaction.

1. The Steps to make a transaction

Making bundle include all inputs and outputs

  1. Prepare output transactions
  2. Prepare input transactions until input value fulfill output value
  3. Finalized bundle to get bundle hash and filling into all transaction
  4. Singing transactions to filling signature message fragment

Get two tips for trunk and branch hash

via IRI getTransactionsToApprove

Proof of Work

  1. Fill up trunk and branch hash to transaction
  2. Fill up tag with obsolete tag if tag is not set
  3. Fill up timestamp to transaction
  4. Calculate nonce via pearlDiver and get transaction hash

At the end of this, we will get transaction trytes which include all elements that we need (bundle hash, branch / trunk hash, nonce, and transaction has).

2. Making bundle

In IOTA bundle, you can find three type of transaction include in it. Input transactionOutput transaction, and Meta transaction.

  • Input transaction: transaction value is negative.
  • Output transaction: transaction value is positive.
  • Meta transaction: transaction value is 0, it can be the carieer of signature, or save other message in transaction’s siganture message fragment.

Let’s take an example, A has 3 address from same seed, with some value:

index 0: AAAAAAAA, balance: 50
index 1: BBBBBBBB, balance: 70
index 2: CCCCCCCC, balance: 20

When A what to send 100i to B’s address DDDDDDDD, IOTA will do something like this:

Gather all transaction we need in bundle

  • Prepare output transaction to B’s address and add into bundle
  • Prepare input transaction from A’s address with balance
  • Add each input transaction into bundle with meta transaction slot

meta transaction slot amount will depend on address security level, default security level of address is 2, that means we will need one additional transaction to carrying transaction signature.

  • If the balance of bundle is still positive, add in an unspent output transaction to move unspent value

Bundle finalized

  • Check bundle balance is 0 (that input value = output value)

Generate bundle hash

  • absorb with transaction validate item (address, value, obsolete tag, timestamp, current index, and last index)
  • squeeze out bundle trits and convert to bundle hash
  • Check if generate a secure bundle hash, if not, increase obsolete tag and regenerate again
  • Fill bundle hash and init signature fragment to all transaction
  • notice that transaction hash, transaction tips, signature fragment and nonce are not filling in this step, only bundle hash is determined.

Bundle signing

  • Get key generator via seed
  • Iterate through transactions, if transaction is an output transaction, it will try to signing this transaction (with meta transaction if needed)
  • Get address private key via key generate with address index and security level
  • Using address private key and bundle hash to generate signature fragment and filling into transaction’s signature fragment part.
  • If the security level is 2, then we will need to sign up two transaction (1 for output transaction and the following meta transaction)

At the end of this step, we will get a list of transaction trytes that including bundle hash and transaction signature with the reverse direction (from the last index to 0 index).

3. Get two tips for trunk and branch

In this article I will not cover the MCMC algorithm, think this as a black box that we can get two tips from IRI via getTransactionsToApprove.

4. Proof of Work

In the last step, we will need to fill-up trunk, branch, and find nonce (Proof of Work here!) into each transaction in the bundle.

As bundles documentation mention, a bundle is an atomic transfer item in the tangle, which means in one bundle, they will have the same tips.

It will then walk through all transactions in the bundle from the last index to 0 index, to fill-up trunk, branch hash, timestamp, and then do PoW (pearlDiver) to find nonce and generate transaction hash, then validated the PoW result.

Last index’s transaction trunk and branch hash will be previous tips we get. Other transaction’s trunk will be previous transaction’s hash, and branch hash is trunk transaction from tips.

The diagram of transaction trunk and branch

If everything is fine, we then can get the full transactions trytes with all field be filled in!

5. PoC code from Python with PyOTA

# -*- coding: utf-8 -*-
# This is a POC code to generate IOTA transaction and bundle
# Note: You will need to implement getTransactionsToApprove and pearlDiver

import iota


tag = iota.Tag('TESTINGPYTHON')
pt = iota.ProposedTransaction(

pb = iota.ProposedBundle([pt])

# pb.add_inputs([list])
#  pb._create_input_transaction(addy)

addy.balance = 100
addy.key_index = 2
addy.security_level = 2
inputs = [
for input in inputs:
for _ in range(addy.security_level - 1):

# send unspent inputs to

# This will get the bundle hash

# If the transaction need sign, it will then sign-up the transaction
# to fill up signature fragements
kg = iota.crypto.signing.KeyGenerator(SEED)

# pb.sign_inputs(kg)
i = 0
while i < len(pb):
    txn = pb[i]
    if txn.value < 0:
        if txn.address.key_index is None or txn.address.security_level is None:
            raise ValueError
        # pb.sign_input_at(i, kg.get_key_for(txn.address))
        address_priv_key = kg.get_key_for(txn.address)

        # Fill in signature fragement
        # address_priv_key.sign_input_transactions(pb, i)
        from iota.crypto.signing import SignatureFragmentGenerator
        sfg = SignatureFragmentGenerator(address_priv_key, pb.hash)
        for j in range(address_priv_key.security_level):
            txn = pb[i + j]
            txnt.signature_message_fragment = next(sfg)
        i += txn.address.security_level
        i += 1

# Now each transaction have their signature into bundle
# this is the end of the transaction construction.
# We can now propose the transaction to tangle
# At this moment, tips still not inside each transaction,
# and each transaction hash is not yet generated
trytes = pb.as_tryte_strings()

# Get tips by getTransactionsToApprove
# tips = getTransactionsToApprove()
trunk_hash = iota.Hash('')
branch_hash = iota.Hash('')

# Do PoW (attach to tangle)
prev_tx = None

for tx_tryte in trytes:
    txn = iota.Transaction.from_tryte_string(tx_tryte)
    txn.trunk_transaction_hash = trunk_hash if prev_tx is None else prev_tx.hash
    txn.branch_transaction_hash = branch_hash if prev_tx is None else trunk_hash

    # Copy obsolete tag if tag field is empty
    if not txn.tag:
        txn.tag = txn.obsolete_tag

    # Copy timestamp
    txn.timestamp = None
    txn.timestamp_lower_bound = None
    txn.timestamp_upper_bound = None

    # Do the PoW for this transaction
    #, min_weight_magniude, 0)

    # Validate PoW
    # transactionValidator.validate(txn.as_trits())

6. Conclusion

Here we describe how IOTA construct a bundle with transactions, and when it fill-up some critical parts of the transaction, such as bundle hash, transaction hash, trunk hash, branch hash, and nonce.

If you like this article, welcome to donate IOTA to


One Reply to “In depth explanation of how IOTA making a transaction”

  1. The following time I read a blog, I hope that it doesnt disappoint me as much as this one. I mean, I know it was my option to learn, but I really thought youd have something fascinating to say. All I hear is a bunch of whining about one thing that you might repair in the event you werent too busy in search of attention.

Leave a Reply

Your email address will not be published. Required fields are marked *