diff --git a/packages/binary/valuetransfer/address/address.go b/packages/binary/valuetransfer/address/address.go
index 26bfa6f28daa4361897509849fc0ef4a58b3fb76..38fd22c166ddc8488766906c11fd7c93f029e869 100644
--- a/packages/binary/valuetransfer/address/address.go
+++ b/packages/binary/valuetransfer/address/address.go
@@ -34,6 +34,12 @@ func Random() (address Address) {
 	return
 }
 
+func RandomOfType(versionByte byte) Address {
+	ret := Random()
+	ret[0] = versionByte
+	return ret
+}
+
 // FromBase58 creates an address from a base58 encoded string.
 func FromBase58(base58String string) (address Address, err error) {
 	// decode string
diff --git a/packages/binary/valuetransfer/tangle/tangle.go b/packages/binary/valuetransfer/tangle/tangle.go
index a1aef9b378268a9383397b412106ddbdd3e02ada..e9e51e71161e1baa7e0fee6b1319c7246d48b3e5 100644
--- a/packages/binary/valuetransfer/tangle/tangle.go
+++ b/packages/binary/valuetransfer/tangle/tangle.go
@@ -70,7 +70,7 @@ func (tangle *Tangle) AttachPayload(payload *payload.Payload) {
 	tangle.storePayloadWorkerPool.Submit(func() { tangle.storePayloadWorker(payload) })
 }
 
-// GetPayload retrieves a payload from the object storage.
+// GetDataPayload retrieves a payload from the object storage.
 func (tangle *Tangle) GetPayload(payloadId payload.Id) *payload.CachedPayload {
 	return &payload.CachedPayload{CachedObject: tangle.payloadStorage.Load(payloadId.Bytes())}
 }
diff --git a/packages/binary/valuetransfer/transaction/transaction.go b/packages/binary/valuetransfer/transaction/transaction.go
index 04e3ab016273f6e34586f595f58aa4b8aefdbfc4..9c1560e3533c533857ed7fb7de0e678109684a64 100644
--- a/packages/binary/valuetransfer/transaction/transaction.go
+++ b/packages/binary/valuetransfer/transaction/transaction.go
@@ -32,6 +32,10 @@ type Transaction struct {
 	signatureBytes      []byte
 	signatureBytesMutex sync.RWMutex
 
+	dataPayloadType  uint32
+	dataPayload      []byte
+	dataPayloadMutex sync.RWMutex
+
 	bytes      []byte
 	bytesMutex sync.RWMutex
 }
@@ -182,6 +186,15 @@ func (transaction *Transaction) EssenceBytes() []byte {
 	// marshal outputs
 	marshalUtil.WriteBytes(transaction.outputs.Bytes())
 
+	// marshal dataPayload type
+	marshalUtil.WriteUint32(transaction.dataPayloadType)
+
+	// marshal dataPayload size
+	marshalUtil.WriteUint32(transaction.DataPayloadSize())
+
+	// marshal dataPayload data
+	marshalUtil.WriteBytes(transaction.dataPayload)
+
 	// store marshaled result
 	transaction.essenceBytes = marshalUtil.Bytes()
 
@@ -260,9 +273,43 @@ func (transaction *Transaction) String() string {
 		stringify.StructField("inputs", transaction.inputs),
 		stringify.StructField("outputs", transaction.outputs),
 		stringify.StructField("signatures", transaction.signatures),
+		stringify.StructField("dataPayloadSize", transaction.DataPayloadSize()),
 	)
 }
 
+// max dataPayload size limit
+const MAX_DATA_PAYLOAD_SIZE = 64 * 1024
+
+// sets yhe dataPayload and its type
+func (transaction *Transaction) SetDataPayload(data []byte, payloadType uint32) error {
+	transaction.dataPayloadMutex.Lock()
+	defer transaction.dataPayloadMutex.Unlock()
+
+	if len(data) > MAX_DATA_PAYLOAD_SIZE {
+		return fmt.Errorf("maximum dataPayload size of %d bytes exceeded", MAX_DATA_PAYLOAD_SIZE)
+	}
+	transaction.dataPayload = data
+	transaction.dataPayloadType = payloadType
+	return nil
+}
+
+// gets the dataPayload and its type
+func (transaction *Transaction) GetDataPayload() ([]byte, uint32) {
+	transaction.dataPayloadMutex.RLock()
+	defer transaction.dataPayloadMutex.RUnlock()
+
+	return transaction.dataPayload, transaction.dataPayloadType
+}
+
+// return size of the dataPayload as uint32
+// nil payload as size 0
+func (transaction *Transaction) DataPayloadSize() uint32 {
+	transaction.dataPayloadMutex.RLock()
+	defer transaction.dataPayloadMutex.RUnlock()
+
+	return uint32(len(transaction.dataPayload))
+}
+
 // endregion ///////////////////////////////////////////////////////////////////////////////////////////////////////////
 
 // region IMPLEMENT StorableObject interface ///////////////////////////////////////////////////////////////////////////
@@ -301,6 +348,30 @@ func (transaction *Transaction) UnmarshalObjectStorageValue(bytes []byte) (err e
 	}
 	transaction.outputs = parsedOutputs.(*Outputs)
 
+	// unmarshal data payload type
+	transaction.dataPayloadType, err = marshalUtil.ReadUint32()
+	if err != nil {
+		return
+	}
+
+	// unmarshal data payload size
+	var dataPayloadSize uint32
+	dataPayloadSize, err = marshalUtil.ReadUint32()
+	if err != nil {
+		return
+	}
+	if dataPayloadSize > MAX_DATA_PAYLOAD_SIZE {
+		err = fmt.Errorf("data payload size of %d bytes exceeds maximum limit of %d bytes",
+			dataPayloadSize, MAX_DATA_PAYLOAD_SIZE)
+		return
+	}
+
+	// unmarshal data payload
+	transaction.dataPayload, err = marshalUtil.ReadBytes(int(dataPayloadSize))
+	if err != nil {
+		return
+	}
+
 	// store essence bytes
 	essenceBytesCount := marshalUtil.ReadOffset()
 	transaction.essenceBytes = make([]byte, essenceBytesCount)
diff --git a/packages/binary/valuetransfer/transaction/transaction_test.go b/packages/binary/valuetransfer/transaction/transaction_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..ec16af7f8104b1329bafe781ca3c4be6b2718185
--- /dev/null
+++ b/packages/binary/valuetransfer/transaction/transaction_test.go
@@ -0,0 +1,128 @@
+package transaction
+
+import (
+	"bytes"
+	"github.com/iotaledger/goshimmer/packages/binary/valuetransfer/address"
+	"github.com/iotaledger/goshimmer/packages/binary/valuetransfer/address/signaturescheme"
+	"github.com/iotaledger/goshimmer/packages/binary/valuetransfer/balance"
+	"github.com/iotaledger/hive.go/crypto/ed25519"
+	"github.com/stretchr/testify/assert"
+	"strings"
+	"testing"
+)
+
+func TestEmptyDataPayload(t *testing.T) {
+	sigScheme := signaturescheme.ED25519(ed25519.GenerateKeyPair())
+	addr := sigScheme.Address()
+	o1 := NewOutputId(addr, RandomId())
+	inputs := NewInputs(o1)
+	bal := balance.New(balance.COLOR_IOTA, 1)
+	outputs := NewOutputs(map[address.Address][]*balance.Balance{addr: {bal}})
+	tx := New(inputs, outputs)
+	tx.Sign(sigScheme)
+	check := tx.SignaturesValid()
+
+	assert.Equal(t, true, check)
+}
+
+func TestShortDataPayload(t *testing.T) {
+	sigScheme := signaturescheme.ED25519(ed25519.GenerateKeyPair())
+	addr := sigScheme.Address()
+	o1 := NewOutputId(addr, RandomId())
+	inputs := NewInputs(o1)
+	bal := balance.New(balance.COLOR_IOTA, 1)
+	outputs := NewOutputs(map[address.Address][]*balance.Balance{addr: {bal}})
+	tx := New(inputs, outputs)
+
+	dataPayload := []byte("data payload test")
+	dataPayloadType := uint32(42)
+	err := tx.SetDataPayload(dataPayload, dataPayloadType)
+	assert.Equal(t, nil, err)
+
+	dpBack, dptBack := tx.GetDataPayload()
+	assert.Equal(t, true, bytes.Compare(dpBack, dataPayload) == 0)
+	assert.Equal(t, true, dptBack == dataPayloadType)
+
+	tx.Sign(sigScheme)
+	check := tx.SignaturesValid()
+	assert.Equal(t, true, check)
+
+	// corrupt data payload bytes
+	// reset essence to force recalculation
+	tx.essenceBytes = nil
+	dataPayload[2] = '?'
+	err = tx.SetDataPayload(dataPayload, dataPayloadType)
+	assert.Equal(t, nil, err)
+
+	// expect signature is not valid
+	check = tx.SignaturesValid()
+	assert.Equal(t, false, check)
+}
+
+func TestTooLongDataPayload(t *testing.T) {
+	sigScheme := signaturescheme.ED25519(ed25519.GenerateKeyPair())
+	addr := sigScheme.Address()
+	o1 := NewOutputId(addr, RandomId())
+	inputs := NewInputs(o1)
+	bal := balance.New(balance.COLOR_IOTA, 1)
+	outputs := NewOutputs(map[address.Address][]*balance.Balance{addr: {bal}})
+	tx := New(inputs, outputs)
+
+	dataPayload := []byte(strings.Repeat("1", MAX_DATA_PAYLOAD_SIZE+1))
+	dataPayloadType := uint32(42)
+	err := tx.SetDataPayload(dataPayload, dataPayloadType)
+	assert.Equal(t, true, err != nil)
+}
+
+func TestMarshalingEmptyDataPayload(t *testing.T) {
+	sigScheme := signaturescheme.RandBLS()
+	addr := sigScheme.Address()
+	o1 := NewOutputId(addr, RandomId())
+	inputs := NewInputs(o1)
+	bal := balance.New(balance.COLOR_IOTA, 1)
+	outputs := NewOutputs(map[address.Address][]*balance.Balance{addr: {bal}})
+	tx := New(inputs, outputs)
+
+	tx.Sign(sigScheme)
+	check := tx.SignaturesValid()
+	assert.Equal(t, true, check)
+
+	v := tx.ObjectStorageValue()
+
+	tx1 := Transaction{}
+	err, _ := tx1.UnmarshalObjectStorageValue(v)
+	if err != nil {
+		assert.Error(t, err)
+	}
+	assert.Equal(t, true, tx1.SignaturesValid())
+	assert.Equal(t, true, bytes.Compare(tx1.Id().Bytes(), tx.Id().Bytes()) == 0)
+}
+
+func TestMarshalingDataPayload(t *testing.T) {
+	sigScheme := signaturescheme.RandBLS()
+	addr := sigScheme.Address()
+	o1 := NewOutputId(addr, RandomId())
+	inputs := NewInputs(o1)
+	bal := balance.New(balance.COLOR_IOTA, 1)
+	outputs := NewOutputs(map[address.Address][]*balance.Balance{addr: {bal}})
+	tx := New(inputs, outputs)
+
+	dataPayload := []byte("data payload test")
+	dataPayloadType := uint32(42)
+	err := tx.SetDataPayload(dataPayload, dataPayloadType)
+	assert.Equal(t, nil, err)
+
+	tx.Sign(sigScheme)
+	check := tx.SignaturesValid()
+	assert.Equal(t, true, check)
+
+	v := tx.ObjectStorageValue()
+
+	tx1 := Transaction{}
+	err, _ = tx1.UnmarshalObjectStorageValue(v)
+
+	assert.Equal(t, nil, err)
+	assert.Equal(t, true, tx1.SignaturesValid())
+
+	assert.Equal(t, true, bytes.Compare(tx1.Id().Bytes(), tx.Id().Bytes()) == 0)
+}