diff --git a/go.mod b/go.mod
index 5cbc7fa9b22bb6fd8c9595d570bf2091c9e45d08..0d6f461262c8db03d1bdbfef0c4e0480726e0e9a 100644
--- a/go.mod
+++ b/go.mod
@@ -10,7 +10,7 @@ require (
 	github.com/googollee/go-engine.io v1.4.3-0.20190924125625-798118fc0dd2
 	github.com/googollee/go-socket.io v1.4.3-0.20191204093753-683f8725b6d0
 	github.com/gorilla/websocket v1.4.1
-	github.com/iotaledger/hive.go v0.0.0-20200323150914-f38e680ea7d1
+	github.com/iotaledger/hive.go v0.0.0-20200325224052-ac4d38108211
 	github.com/iotaledger/iota.go v1.0.0-beta.14
 	github.com/labstack/echo v3.3.10+incompatible
 	github.com/labstack/gommon v0.3.0 // indirect
@@ -30,5 +30,3 @@ require (
 	golang.org/x/net v0.0.0-20200301022130-244492dfa37a
 	gopkg.in/src-d/go-git.v4 v4.13.1
 )
-
-replace github.com/iotaledger/hive.go v0.0.0 => ../hive.go
diff --git a/go.sum b/go.sum
index af601bdf46103e7eb133b073fe777dc340cddce7..16b57bbd2bc00f47c4b440ce912a0d3fc7a62326 100644
--- a/go.sum
+++ b/go.sum
@@ -130,10 +130,10 @@ github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T
 github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
 github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
 github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
-github.com/iotaledger/hive.go v0.0.0-20200319204115-e052cf07c81d h1:bwrSVMHIVROkg6wkdg2MmMRrzRwGORjNBl7LHJzp3+0=
-github.com/iotaledger/hive.go v0.0.0-20200319204115-e052cf07c81d/go.mod h1:EfH+ZcYGFJzzoFpO7NHGi2k7+Xc84ASyp1EwjhI3eJc=
-github.com/iotaledger/hive.go v0.0.0-20200323150914-f38e680ea7d1 h1:ActziRcYMPDnccHya7NKtwsPCIL5B9WcSE/g6ZFcAew=
-github.com/iotaledger/hive.go v0.0.0-20200323150914-f38e680ea7d1/go.mod h1:EfH+ZcYGFJzzoFpO7NHGi2k7+Xc84ASyp1EwjhI3eJc=
+github.com/iotaledger/hive.go v0.0.0-20200325224052-ac4d38108211 h1:ckZnjlKHCqgsG6jV5EEyI4uSXElOJxLN1fwQHc4r+eM=
+github.com/iotaledger/hive.go v0.0.0-20200325224052-ac4d38108211/go.mod h1:EfH+ZcYGFJzzoFpO7NHGi2k7+Xc84ASyp1EwjhI3eJc=
+github.com/iotaledger/hive.go v0.0.0-20200326125723-9ba81bd19b75 h1:oZdDKfciKDJm/txN1/Ax61CCuFyOc7Y7mpMCrrgCVwo=
+github.com/iotaledger/hive.go v0.0.0-20200326125723-9ba81bd19b75/go.mod h1:EfH+ZcYGFJzzoFpO7NHGi2k7+Xc84ASyp1EwjhI3eJc=
 github.com/iotaledger/iota.go v1.0.0-beta.9/go.mod h1:F6WBmYd98mVjAmmPVYhnxg8NNIWCjjH8VWT9qvv3Rc8=
 github.com/iotaledger/iota.go v1.0.0-beta.14 h1:Oeb28MfBuJEeXcGrLhTCJFtbsnc8y1u7xidsAmiOD5A=
 github.com/iotaledger/iota.go v1.0.0-beta.14/go.mod h1:F6WBmYd98mVjAmmPVYhnxg8NNIWCjjH8VWT9qvv3Rc8=
@@ -319,6 +319,7 @@ go.dedis.ch/kyber/v3 v3.0.12 h1:15d61EyBcBoFIS97kS2c/Vz4o3FR8ALnZ2ck9J/ebYM=
 go.dedis.ch/kyber/v3 v3.0.12/go.mod h1:kXy7p3STAurkADD+/aZcsznZGKVHEqbtmdIzvPfrs1U=
 go.dedis.ch/protobuf v1.0.5/go.mod h1:eIV4wicvi6JK0q/QnfIEGeSFNG0ZeB24kzut5+HaRLo=
 go.dedis.ch/protobuf v1.0.7/go.mod h1:pv5ysfkDX/EawiPqcW3ikOxsL5t+BqnV6xHSmE79KI4=
+go.dedis.ch/protobuf v1.0.11 h1:FTYVIEzY/bfl37lu3pR4lIj+F9Vp1jE8oh91VmxKgLo=
 go.dedis.ch/protobuf v1.0.11/go.mod h1:97QR256dnkimeNdfmURz0wAMNVbd1VmLXhG1CrTYrJ4=
 go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
 go.mongodb.org/mongo-driver v1.0.0/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
diff --git a/packages/binary/marshalutil/marshalutil.bool.go b/packages/binary/marshalutil/marshalutil.bool.go
deleted file mode 100644
index ab1467f13cd19330fa985206d6b5dc6daa175da9..0000000000000000000000000000000000000000
--- a/packages/binary/marshalutil/marshalutil.bool.go
+++ /dev/null
@@ -1,24 +0,0 @@
-package marshalutil
-
-func (util *MarshalUtil) WriteBool(bool bool) {
-	writeEndOffset := util.expandWriteCapacity(1)
-
-	if bool {
-		util.bytes[util.writeOffset] = 1
-	} else {
-		util.bytes[util.writeOffset] = 0
-	}
-
-	util.WriteSeek(writeEndOffset)
-}
-
-func (util *MarshalUtil) ReadBool() (bool, error) {
-	readEndOffset, err := util.checkReadCapacity(1)
-	if err != nil {
-		return false, err
-	}
-
-	defer util.ReadSeek(readEndOffset)
-
-	return util.bytes[util.readOffset] == 1, nil
-}
diff --git a/packages/binary/marshalutil/marshalutil.byte.go b/packages/binary/marshalutil/marshalutil.byte.go
deleted file mode 100644
index 37e15bf71d31107e46f59e2e0c52fed7566d14e5..0000000000000000000000000000000000000000
--- a/packages/binary/marshalutil/marshalutil.byte.go
+++ /dev/null
@@ -1,20 +0,0 @@
-package marshalutil
-
-func (util *MarshalUtil) WriteByte(byte byte) {
-	writeEndOffset := util.expandWriteCapacity(1)
-
-	util.bytes[util.writeOffset] = byte
-
-	util.WriteSeek(writeEndOffset)
-}
-
-func (util *MarshalUtil) ReadByte() (byte, error) {
-	readEndOffset, err := util.checkReadCapacity(1)
-	if err != nil {
-		return 0, err
-	}
-
-	defer util.ReadSeek(readEndOffset)
-
-	return util.bytes[util.readOffset], nil
-}
diff --git a/packages/binary/marshalutil/marshalutil.bytes.go b/packages/binary/marshalutil/marshalutil.bytes.go
deleted file mode 100644
index 9e58affdf422462de2011713f3b31e93fb588d53..0000000000000000000000000000000000000000
--- a/packages/binary/marshalutil/marshalutil.bytes.go
+++ /dev/null
@@ -1,39 +0,0 @@
-package marshalutil
-
-// WriteBytes appends the given bytes to the internal buffer.
-// It returns the same MarshalUtil so calls can be chained.
-func (util *MarshalUtil) WriteBytes(bytes []byte) *MarshalUtil {
-	if bytes == nil {
-		return util
-	}
-
-	writeEndOffset := util.expandWriteCapacity(len(bytes))
-
-	copy(util.bytes[util.writeOffset:writeEndOffset], bytes)
-
-	util.WriteSeek(writeEndOffset)
-
-	return util
-}
-
-// ReadBytes unmarshals the given amount of bytes from the internal read buffer.
-func (util *MarshalUtil) ReadBytes(length int) ([]byte, error) {
-	if length < 0 {
-		length = len(util.bytes) - util.readOffset + length
-	}
-
-	readEndOffset, err := util.checkReadCapacity(length)
-	if err != nil {
-		return nil, err
-	}
-
-	defer util.ReadSeek(readEndOffset)
-
-	return util.bytes[util.readOffset:readEndOffset], nil
-}
-
-func (util *MarshalUtil) ReadRemainingBytes() []byte {
-	defer util.ReadSeek(util.size)
-
-	return util.bytes[util.readOffset:]
-}
diff --git a/packages/binary/marshalutil/marshalutil.go b/packages/binary/marshalutil/marshalutil.go
deleted file mode 100644
index 87837b836e27401d660a2cd0db70364244d75a1b..0000000000000000000000000000000000000000
--- a/packages/binary/marshalutil/marshalutil.go
+++ /dev/null
@@ -1,105 +0,0 @@
-package marshalutil
-
-import (
-	"fmt"
-)
-
-type MarshalUtil struct {
-	bytes       []byte
-	readOffset  int
-	writeOffset int
-	size        int
-}
-
-func New(args ...interface{}) *MarshalUtil {
-	switch argsCount := len(args); argsCount {
-	case 0:
-		return &MarshalUtil{
-			bytes: make([]byte, 1024),
-			size:  0,
-		}
-	case 1:
-		switch param := args[0].(type) {
-		case int:
-			return &MarshalUtil{
-				bytes: make([]byte, param),
-				size:  param,
-			}
-		case []byte:
-			return &MarshalUtil{
-				bytes: param,
-				size:  len(param),
-			}
-		default:
-			panic(fmt.Errorf("illegal argument type %T in marshalutil.New(...)", param))
-		}
-	default:
-		panic(fmt.Errorf("illegal argument count %d in marshalutil.New(...)", argsCount))
-	}
-}
-
-func (util *MarshalUtil) Parse(parser func(data []byte) (interface{}, error, int)) (result interface{}, err error) {
-	result, err, readBytes := parser(util.bytes[util.readOffset:])
-	if err == nil {
-		util.ReadSeek(util.readOffset + readBytes)
-	}
-
-	return
-}
-
-func (util *MarshalUtil) ReadOffset() int {
-	return util.readOffset
-}
-
-func (util *MarshalUtil) WriteOffset() int {
-	return util.writeOffset
-}
-
-func (util *MarshalUtil) WriteSeek(offset int) {
-	if offset < 0 {
-		util.writeOffset += offset
-	} else {
-		util.writeOffset = offset
-	}
-}
-
-func (util *MarshalUtil) ReadSeek(offset int) {
-	if offset < 0 {
-		util.readOffset += offset
-	} else {
-		util.readOffset = offset
-	}
-}
-
-func (util *MarshalUtil) Bytes(clone ...bool) []byte {
-	if len(clone) >= 1 && clone[0] {
-		clone := make([]byte, util.size)
-		copy(clone, util.bytes)
-
-		return clone
-	}
-
-	return util.bytes[:util.size]
-}
-
-func (util *MarshalUtil) checkReadCapacity(length int) (readEndOffset int, err error) {
-	readEndOffset = util.readOffset + length
-
-	if readEndOffset > util.size {
-		err = fmt.Errorf("tried to read %d bytes from %d bytes input", readEndOffset, util.size)
-	}
-
-	return
-}
-
-func (util *MarshalUtil) expandWriteCapacity(length int) (writeEndOffset int) {
-	writeEndOffset = util.writeOffset + length
-
-	if writeEndOffset > util.size {
-		extendedBytes := make([]byte, writeEndOffset-util.size)
-		util.bytes = append(util.bytes, extendedBytes...)
-		util.size = writeEndOffset
-	}
-
-	return
-}
diff --git a/packages/binary/marshalutil/marshalutil.int64.go b/packages/binary/marshalutil/marshalutil.int64.go
deleted file mode 100644
index 5f1e55754abe159ab0df532234f5b8535eb77eb6..0000000000000000000000000000000000000000
--- a/packages/binary/marshalutil/marshalutil.int64.go
+++ /dev/null
@@ -1,26 +0,0 @@
-package marshalutil
-
-import (
-	"encoding/binary"
-)
-
-const INT64_SIZE = 8
-
-func (util *MarshalUtil) WriteInt64(value int64) {
-	writeEndOffset := util.expandWriteCapacity(INT64_SIZE)
-
-	binary.LittleEndian.PutUint64(util.bytes[util.writeOffset:writeEndOffset], uint64(value))
-
-	util.WriteSeek(writeEndOffset)
-}
-
-func (util *MarshalUtil) ReadInt64() (int64, error) {
-	readEndOffset, err := util.checkReadCapacity(INT64_SIZE)
-	if err != nil {
-		return 0, err
-	}
-
-	defer util.ReadSeek(readEndOffset)
-
-	return int64(binary.LittleEndian.Uint64(util.bytes[util.readOffset:readEndOffset])), nil
-}
diff --git a/packages/binary/marshalutil/marshalutil.time.go b/packages/binary/marshalutil/marshalutil.time.go
deleted file mode 100644
index 36633dd9d878dcf9d065dbe1b2a3272fe578a1d6..0000000000000000000000000000000000000000
--- a/packages/binary/marshalutil/marshalutil.time.go
+++ /dev/null
@@ -1,33 +0,0 @@
-package marshalutil
-
-import (
-	"time"
-)
-
-// WriteTime marshals the given time into a sequence of bytes, that get appended to the internal buffer.
-func (util *MarshalUtil) WriteTime(timeToWrite time.Time) {
-	nanoSeconds := timeToWrite.UnixNano()
-
-	// the zero value of time translates to -6795364578871345152
-	if nanoSeconds == -6795364578871345152 {
-		util.WriteInt64(0)
-	} else {
-		util.WriteInt64(timeToWrite.UnixNano())
-	}
-}
-
-// ReadTime unmarshals a time object from the internal read buffer.
-func (util *MarshalUtil) ReadTime() (result time.Time, err error) {
-	nanoSeconds, err := util.ReadInt64()
-	if err != nil {
-		return
-	}
-
-	if nanoSeconds == 0 {
-		result = time.Time{}
-	} else {
-		result = time.Unix(0, nanoSeconds)
-	}
-
-	return
-}
diff --git a/packages/binary/marshalutil/marshalutil.uint32.go b/packages/binary/marshalutil/marshalutil.uint32.go
deleted file mode 100644
index 473e1d505100c96a5f156b0a42ce033bd6924313..0000000000000000000000000000000000000000
--- a/packages/binary/marshalutil/marshalutil.uint32.go
+++ /dev/null
@@ -1,26 +0,0 @@
-package marshalutil
-
-import (
-	"encoding/binary"
-)
-
-const UINT32_SIZE = 4
-
-func (util *MarshalUtil) WriteUint32(value uint32) {
-	writeEndOffset := util.expandWriteCapacity(UINT32_SIZE)
-
-	binary.LittleEndian.PutUint32(util.bytes[util.writeOffset:writeEndOffset], value)
-
-	util.WriteSeek(writeEndOffset)
-}
-
-func (util *MarshalUtil) ReadUint32() (uint32, error) {
-	readEndOffset, err := util.checkReadCapacity(UINT32_SIZE)
-	if err != nil {
-		return 0, err
-	}
-
-	defer util.ReadSeek(readEndOffset)
-
-	return binary.LittleEndian.Uint32(util.bytes[util.readOffset:readEndOffset]), nil
-}
diff --git a/packages/binary/marshalutil/marshalutil.uint64.go b/packages/binary/marshalutil/marshalutil.uint64.go
deleted file mode 100644
index 0bb33119de4cf8b337998ea119f2bd138ef977e3..0000000000000000000000000000000000000000
--- a/packages/binary/marshalutil/marshalutil.uint64.go
+++ /dev/null
@@ -1,24 +0,0 @@
-package marshalutil
-
-import "encoding/binary"
-
-const UINT64_SIZE = 8
-
-func (util *MarshalUtil) WriteUint64(value uint64) {
-	writeEndOffset := util.expandWriteCapacity(UINT64_SIZE)
-
-	binary.LittleEndian.PutUint64(util.bytes[util.writeOffset:writeEndOffset], value)
-
-	util.WriteSeek(writeEndOffset)
-}
-
-func (util *MarshalUtil) ReadUint64() (uint64, error) {
-	readEndOffset, err := util.checkReadCapacity(UINT64_SIZE)
-	if err != nil {
-		return 0, err
-	}
-
-	defer util.ReadSeek(readEndOffset)
-
-	return binary.LittleEndian.Uint64(util.bytes[util.readOffset:readEndOffset]), nil
-}
diff --git a/packages/binary/marshalutil/marshalutil_test.go b/packages/binary/marshalutil/marshalutil_test.go
deleted file mode 100644
index 17605b2140af0de9c4673c264f9b7787f7c926ac..0000000000000000000000000000000000000000
--- a/packages/binary/marshalutil/marshalutil_test.go
+++ /dev/null
@@ -1,22 +0,0 @@
-package marshalutil
-
-import (
-	"fmt"
-	"testing"
-)
-
-func Test(t *testing.T) {
-	util := New(1)
-
-	util.WriteBytes(make([]byte, UINT64_SIZE))
-	util.WriteInt64(-12)
-	util.WriteUint64(38)
-	util.WriteUint64(38)
-
-	fmt.Println(util.ReadBytes(UINT64_SIZE))
-	fmt.Println(util.ReadInt64())
-	fmt.Println(util.ReadUint64())
-	fmt.Println(util.ReadUint64())
-
-	fmt.Println(util)
-}
diff --git a/packages/binary/signature/ed25119/public_key.go b/packages/binary/signature/ed25119/public_key.go
index f050f6ff274fc6bbb19f6a9dd1c105465fea551c..485ac0fea375198359c8de9f0258c37772692979 100644
--- a/packages/binary/signature/ed25119/public_key.go
+++ b/packages/binary/signature/ed25119/public_key.go
@@ -4,9 +4,8 @@ import (
 	"errors"
 	"fmt"
 
+	"github.com/iotaledger/hive.go/marshalutil"
 	"github.com/oasislabs/ed25519"
-
-	"github.com/iotaledger/goshimmer/packages/binary/marshalutil"
 )
 
 type PublicKey [PublicKeySize]byte
diff --git a/packages/binary/signature/ed25119/signature.go b/packages/binary/signature/ed25119/signature.go
index 01a6750f7b62cb1c9b5653ef272bd9d4fee3c1b9..6362dce52d02efa74e361fa54f3aa6ccf1e7d977 100644
--- a/packages/binary/signature/ed25119/signature.go
+++ b/packages/binary/signature/ed25119/signature.go
@@ -4,7 +4,7 @@ import (
 	"errors"
 	"fmt"
 
-	"github.com/iotaledger/goshimmer/packages/binary/marshalutil"
+	"github.com/iotaledger/hive.go/marshalutil"
 )
 
 type Signature [SignatureSize]byte
diff --git a/packages/binary/storageprefix/storageprefix.go b/packages/binary/storageprefix/storageprefix.go
index d288fb2db1a15ff0d9245d8c2f8748d401534acc..0c960b0ac2102861550b75f15b0f84c86393497e 100644
--- a/packages/binary/storageprefix/storageprefix.go
+++ b/packages/binary/storageprefix/storageprefix.go
@@ -12,9 +12,11 @@ var (
 	ValueTransferPayloadMetadata = []byte{6}
 	ValueTransferApprover        = []byte{7}
 	ValueTransferMissingPayload  = []byte{8}
+	ValueTransferAttachment      = []byte{9}
+	ValueTransferConsumer        = []byte{10}
 
-	LedgerStateTransferOutput        = []byte{9}
-	LedgerStateTransferOutputBooking = []byte{10}
-	LedgerStateReality               = []byte{11}
-	LedgerStateConflictSet           = []byte{12}
+	LedgerStateTransferOutput        = []byte{11}
+	LedgerStateTransferOutputBooking = []byte{12}
+	LedgerStateReality               = []byte{13}
+	LedgerStateConflictSet           = []byte{14}
 )
diff --git a/packages/binary/tangle/model/approver/approver.go b/packages/binary/tangle/model/approver/approver.go
index 23c0842be18b328762caafb230a0025868b4ca8b..b6545c6c4a65fb2ea821d9b33322def2f267e6e3 100644
--- a/packages/binary/tangle/model/approver/approver.go
+++ b/packages/binary/tangle/model/approver/approver.go
@@ -27,7 +27,7 @@ func New(referencedTransaction message.Id, approvingTransaction message.Id) *App
 	return approver
 }
 
-func FromStorage(id []byte) (result objectstorage.StorableObject) {
+func StorableObjectFromKey(id []byte) (result objectstorage.StorableObject, err error) {
 	approver := &Approver{
 		storageKey: make([]byte, message.IdLength+message.IdLength),
 	}
@@ -35,10 +35,10 @@ func FromStorage(id []byte) (result objectstorage.StorableObject) {
 	copy(approver.approvingTransaction[:], id[message.IdLength:])
 	copy(approver.storageKey, id)
 
-	return approver
+	return approver, nil
 }
 
-func (approver *Approver) GetStorageKey() []byte {
+func (approver *Approver) ObjectStorageKey() []byte {
 	return approver.storageKey
 }
 
@@ -50,10 +50,10 @@ func (approver *Approver) Update(other objectstorage.StorableObject) {
 	panic("approvers should never be overwritten and only stored once to optimize IO")
 }
 
-func (approver *Approver) MarshalBinary() (result []byte, err error) {
+func (approver *Approver) ObjectStorageValue() (result []byte) {
 	return
 }
 
-func (approver *Approver) UnmarshalBinary(data []byte) (err error) {
+func (approver *Approver) UnmarshalObjectStorageValue(data []byte) (err error) {
 	return
 }
diff --git a/packages/binary/tangle/model/message/id.go b/packages/binary/tangle/model/message/id.go
index 4060031583911101ef10ab67c45932a86a56e530..c268adbf146c231318a38cd1339d09326d26db2e 100644
--- a/packages/binary/tangle/model/message/id.go
+++ b/packages/binary/tangle/model/message/id.go
@@ -3,9 +3,8 @@ package message
 import (
 	"fmt"
 
+	"github.com/iotaledger/hive.go/marshalutil"
 	"github.com/mr-tron/base58"
-
-	"github.com/iotaledger/goshimmer/packages/binary/marshalutil"
 )
 
 type Id [IdLength]byte
diff --git a/packages/binary/tangle/model/message/payload/data/data.go b/packages/binary/tangle/model/message/payload/data/data.go
index 70efdcfcdaa7b98f2171108ba85cab469851d018..2be4b5db174ae77b06a2d422dfb6760ae5e5edf1 100644
--- a/packages/binary/tangle/model/message/payload/data/data.go
+++ b/packages/binary/tangle/model/message/payload/data/data.go
@@ -1,9 +1,9 @@
 package data
 
 import (
+	"github.com/iotaledger/hive.go/marshalutil"
 	"github.com/iotaledger/hive.go/stringify"
 
-	"github.com/iotaledger/goshimmer/packages/binary/marshalutil"
 	"github.com/iotaledger/goshimmer/packages/binary/tangle/model/message/payload"
 )
 
@@ -55,7 +55,7 @@ func FromBytes(bytes []byte, optionalTargetObject ...*Data) (result *Data, err e
 	return
 }
 
-func (dataPayload *Data) GetType() payload.Type {
+func (dataPayload *Data) Type() payload.Type {
 	return dataPayload.payloadType
 }
 
@@ -69,7 +69,7 @@ func (dataPayload *Data) Bytes() []byte {
 	marshalUtil := marshalutil.New()
 
 	// marshal the payload specific information
-	marshalUtil.WriteUint32(dataPayload.GetType())
+	marshalUtil.WriteUint32(dataPayload.Type())
 	marshalUtil.WriteUint32(uint32(len(dataPayload.data)))
 	marshalUtil.WriteBytes(dataPayload.data[:])
 
@@ -77,16 +77,12 @@ func (dataPayload *Data) Bytes() []byte {
 	return marshalUtil.Bytes()
 }
 
-func (dataPayload *Data) UnmarshalBinary(data []byte) (err error) {
+func (dataPayload *Data) Unmarshal(data []byte) (err error) {
 	_, err, _ = FromBytes(data, dataPayload)
 
 	return
 }
 
-func (dataPayload *Data) MarshalBinary() (data []byte, err error) {
-	return dataPayload.Bytes(), nil
-}
-
 func (dataPayload *Data) String() string {
 	return stringify.Struct("Data",
 		stringify.StructField("data", string(dataPayload.GetData())),
@@ -98,7 +94,7 @@ func GenericPayloadUnmarshalerFactory(payloadType payload.Type) payload.Unmarsha
 		payload = &Data{
 			payloadType: payloadType,
 		}
-		err = payload.UnmarshalBinary(data)
+		err = payload.Unmarshal(data)
 
 		return
 	}
diff --git a/packages/binary/tangle/model/message/payload/payload.go b/packages/binary/tangle/model/message/payload/payload.go
index 06d0d43912b9889493f0a8ba1d72cf7adaed5fec..5510738465f479f462fa5b1db3a999fed438b9da 100644
--- a/packages/binary/tangle/model/message/payload/payload.go
+++ b/packages/binary/tangle/model/message/payload/payload.go
@@ -1,17 +1,13 @@
 package payload
 
 import (
-	"encoding"
-
-	"github.com/iotaledger/goshimmer/packages/binary/marshalutil"
+	"github.com/iotaledger/hive.go/marshalutil"
 )
 
 type Payload interface {
-	encoding.BinaryMarshaler
-	encoding.BinaryUnmarshaler
-
+	Type() Type
 	Bytes() []byte
-	GetType() Type
+	Unmarshal(bytes []byte) error
 	String() string
 }
 
diff --git a/packages/binary/tangle/model/message/test/transaction_test.go b/packages/binary/tangle/model/message/test/transaction_test.go
index 357ec1ba1978454ed0581d9835c55e1f79972d00..be5a61ffe8d24cb5c5ccfedeeecae19325cd6ca7 100644
--- a/packages/binary/tangle/model/message/test/transaction_test.go
+++ b/packages/binary/tangle/model/message/test/transaction_test.go
@@ -23,11 +23,7 @@ func BenchmarkVerifyDataTransactions(b *testing.B) {
 	for i := 0; i < b.N; i++ {
 		tx := message.New(message.EmptyId, message.EmptyId, ed25119.GenerateKeyPair(), time.Now(), 0, data.New([]byte("some data")))
 
-		if marshaledTransaction, err := tx.MarshalBinary(); err != nil {
-			b.Error(err)
-		} else {
-			transactions[i] = marshaledTransaction
-		}
+		transactions[i] = tx.Bytes()
 	}
 
 	b.ResetTimer()
diff --git a/packages/binary/tangle/model/message/transaction.go b/packages/binary/tangle/model/message/transaction.go
index ff3c9c362cdcc4f42e6fb9c6a00d40e9454cd84b..5b9f6785c7124e9d7200ae752f9234b16d4a8793 100644
--- a/packages/binary/tangle/model/message/transaction.go
+++ b/packages/binary/tangle/model/message/transaction.go
@@ -4,9 +4,9 @@ import (
 	"sync"
 	"time"
 
+	"github.com/iotaledger/hive.go/marshalutil"
 	"github.com/iotaledger/hive.go/stringify"
 
-	"github.com/iotaledger/goshimmer/packages/binary/marshalutil"
 	"github.com/iotaledger/goshimmer/packages/binary/signature/ed25119"
 	"github.com/iotaledger/goshimmer/packages/binary/tangle/model/message/payload"
 
@@ -59,7 +59,7 @@ func New(trunkTransactionId Id, branchTransactionId Id, issuerKeyPair ed25119.Ke
 
 // Get's called when we restore a transaction from storage. The bytes and the content will be unmarshaled by an external
 // caller (the objectStorage factory).
-func FromStorage(id []byte) (result objectstorage.StorableObject) {
+func StorableObjectFromKey(id []byte) (result objectstorage.StorableObject, err error) {
 	var transactionId Id
 	copy(transactionId[:], id)
 
@@ -249,17 +249,17 @@ func (transaction *Transaction) Bytes() []byte {
 }
 
 // Since transactions are immutable and do not get changed after being created, we cache the result of the marshaling.
-func (transaction *Transaction) MarshalBinary() (result []byte, err error) {
-	return transaction.Bytes(), nil
+func (transaction *Transaction) ObjectStorageValue() []byte {
+	return transaction.Bytes()
 }
 
-func (transaction *Transaction) UnmarshalBinary(data []byte) (err error) {
+func (transaction *Transaction) UnmarshalObjectStorageValue(data []byte) (err error) {
 	_, err, _ = FromBytes(data, transaction)
 
 	return
 }
 
-func (transaction *Transaction) GetStorageKey() []byte {
+func (transaction *Transaction) ObjectStorageKey() []byte {
 	transactionId := transaction.GetId()
 
 	return transactionId[:]
diff --git a/packages/binary/tangle/model/missingtransaction/missingtransaction.go b/packages/binary/tangle/model/missingtransaction/missingtransaction.go
index 64baa95c546c79f158ae50f4ec14fd4dcfc6b722..a4fc5871dd3b93ee3a122da968c045050b742949 100644
--- a/packages/binary/tangle/model/missingtransaction/missingtransaction.go
+++ b/packages/binary/tangle/model/missingtransaction/missingtransaction.go
@@ -21,11 +21,11 @@ func New(transactionId message.Id) *MissingTransaction {
 	}
 }
 
-func FromStorage(key []byte) objectstorage.StorableObject {
+func StorableObjectFromKey(key []byte) (objectstorage.StorableObject, error) {
 	result := &MissingTransaction{}
 	copy(result.transactionId[:], key)
 
-	return result
+	return result, nil
 }
 
 func (missingTransaction *MissingTransaction) GetTransactionId() message.Id {
@@ -36,18 +36,23 @@ func (missingTransaction *MissingTransaction) GetMissingSince() time.Time {
 	return missingTransaction.missingSince
 }
 
-func (missingTransaction *MissingTransaction) GetStorageKey() []byte {
-	return missingTransaction.transactionId[:]
-}
-
 func (missingTransaction *MissingTransaction) Update(other objectstorage.StorableObject) {
 	panic("missing transactions should never be overwritten and only stored once to optimize IO")
 }
 
-func (missingTransaction *MissingTransaction) MarshalBinary() (result []byte, err error) {
-	return missingTransaction.missingSince.MarshalBinary()
+func (missingTransaction *MissingTransaction) ObjectStorageKey() []byte {
+	return missingTransaction.transactionId[:]
+}
+
+func (missingTransaction *MissingTransaction) ObjectStorageValue() (result []byte) {
+	result, err := missingTransaction.missingSince.MarshalBinary()
+	if err != nil {
+		panic(err)
+	}
+
+	return
 }
 
-func (missingTransaction *MissingTransaction) UnmarshalBinary(data []byte) (err error) {
+func (missingTransaction *MissingTransaction) UnmarshalObjectStorageValue(data []byte) (err error) {
 	return missingTransaction.missingSince.UnmarshalBinary(data)
 }
diff --git a/packages/binary/tangle/model/transactionmetadata/transactionmetadata.go b/packages/binary/tangle/model/transactionmetadata/transactionmetadata.go
index 1fcf1c255093cb2e9f7dec98fae7426e05ed33ec..74e222bbcdfb8face95c981dcfbd0bb75c2cd697 100644
--- a/packages/binary/tangle/model/transactionmetadata/transactionmetadata.go
+++ b/packages/binary/tangle/model/transactionmetadata/transactionmetadata.go
@@ -28,11 +28,11 @@ func New(transactionId message.Id) *TransactionMetadata {
 	}
 }
 
-func FromStorage(id []byte) objectstorage.StorableObject {
+func StorableObjectFromKey(id []byte) (objectstorage.StorableObject, error) {
 	result := &TransactionMetadata{}
 	copy(result.transactionId[:], id)
 
-	return result
+	return result, nil
 }
 
 func (transactionMetadata *TransactionMetadata) IsSolid() (result bool) {
@@ -77,7 +77,7 @@ func (transactionMetadata *TransactionMetadata) GetSoldificationTime() time.Time
 	return transactionMetadata.solidificationTime
 }
 
-func (transactionMetadata *TransactionMetadata) GetStorageKey() []byte {
+func (transactionMetadata *TransactionMetadata) ObjectStorageKey() []byte {
 	return transactionMetadata.transactionId[:]
 }
 
@@ -85,15 +85,15 @@ func (transactionMetadata *TransactionMetadata) Update(other objectstorage.Stora
 
 }
 
-func (transactionMetadata *TransactionMetadata) MarshalBinary() ([]byte, error) {
+func (transactionMetadata *TransactionMetadata) ObjectStorageValue() []byte {
 	return (&Proto{
 		receivedTime:       transactionMetadata.receivedTime,
 		solidificationTime: transactionMetadata.solidificationTime,
 		solid:              transactionMetadata.solid,
-	}).ToBytes(), nil
+	}).ToBytes()
 }
 
-func (transactionMetadata *TransactionMetadata) UnmarshalBinary(data []byte) (err error) {
+func (transactionMetadata *TransactionMetadata) UnmarshalObjectStorageValue(data []byte) (err error) {
 	proto, err := ProtoFromBytes(data)
 	if err != nil {
 		return
@@ -105,3 +105,5 @@ func (transactionMetadata *TransactionMetadata) UnmarshalBinary(data []byte) (er
 
 	return
 }
+
+var _ objectstorage.StorableObject = &TransactionMetadata{}
diff --git a/packages/binary/tangle/tangle.go b/packages/binary/tangle/tangle.go
index ac2418daf5b7619ff920a2029a840f01af177b67..3ed82777a4e82e9e070c53185f5de4b853b9e59f 100644
--- a/packages/binary/tangle/tangle.go
+++ b/packages/binary/tangle/tangle.go
@@ -41,10 +41,10 @@ type Tangle struct {
 func New(badgerInstance *badger.DB, storageId []byte) (result *Tangle) {
 	result = &Tangle{
 		storageId:                  storageId,
-		transactionStorage:         objectstorage.New(badgerInstance, append(storageId, storageprefix.TangleTransaction...), message.FromStorage, objectstorage.CacheTime(10*time.Second), objectstorage.LeakDetectionEnabled(false)),
-		transactionMetadataStorage: objectstorage.New(badgerInstance, append(storageId, storageprefix.TangleTransactionMetadata...), transactionmetadata.FromStorage, objectstorage.CacheTime(10*time.Second), objectstorage.LeakDetectionEnabled(false)),
-		approverStorage:            objectstorage.New(badgerInstance, append(storageId, storageprefix.TangleApprovers...), approver.FromStorage, objectstorage.CacheTime(10*time.Second), objectstorage.PartitionKey(message.IdLength, message.IdLength), objectstorage.LeakDetectionEnabled(false)),
-		missingTransactionsStorage: objectstorage.New(badgerInstance, append(storageId, storageprefix.TangleMissingTransaction...), missingtransaction.FromStorage, objectstorage.CacheTime(10*time.Second), objectstorage.LeakDetectionEnabled(false)),
+		transactionStorage:         objectstorage.New(badgerInstance, append(storageId, storageprefix.TangleTransaction...), message.StorableObjectFromKey, objectstorage.CacheTime(10*time.Second), objectstorage.LeakDetectionEnabled(false)),
+		transactionMetadataStorage: objectstorage.New(badgerInstance, append(storageId, storageprefix.TangleTransactionMetadata...), transactionmetadata.StorableObjectFromKey, objectstorage.CacheTime(10*time.Second), objectstorage.LeakDetectionEnabled(false)),
+		approverStorage:            objectstorage.New(badgerInstance, append(storageId, storageprefix.TangleApprovers...), approver.StorableObjectFromKey, objectstorage.CacheTime(10*time.Second), objectstorage.PartitionKey(message.IdLength, message.IdLength), objectstorage.LeakDetectionEnabled(false)),
+		missingTransactionsStorage: objectstorage.New(badgerInstance, append(storageId, storageprefix.TangleMissingTransaction...), missingtransaction.StorableObjectFromKey, objectstorage.CacheTime(10*time.Second), objectstorage.LeakDetectionEnabled(false)),
 
 		Events: *newEvents(),
 	}
diff --git a/packages/binary/valuetransfer/address/address.go b/packages/binary/valuetransfer/address/address.go
index b73092fd6fd8d9c522be45fd802fda80824088fe..57a024afc6a824a4f5f08b5101d7ac52ad5463be 100644
--- a/packages/binary/valuetransfer/address/address.go
+++ b/packages/binary/valuetransfer/address/address.go
@@ -6,8 +6,8 @@ import (
 	"github.com/mr-tron/base58"
 	"golang.org/x/crypto/blake2b"
 
-	"github.com/iotaledger/goshimmer/packages/binary/marshalutil"
 	"github.com/iotaledger/goshimmer/packages/binary/signature/ed25119"
+	"github.com/iotaledger/hive.go/marshalutil"
 )
 
 type Version = byte
diff --git a/packages/binary/valuetransfer/address/signaturescheme/bls.go b/packages/binary/valuetransfer/address/signaturescheme/bls.go
index 8ff3a296209c9e4eb7da2db0c7bc5e9abc88cd3c..5810effb96ac2842d63212b0a7c3d8d8ff22e7cf 100644
--- a/packages/binary/valuetransfer/address/signaturescheme/bls.go
+++ b/packages/binary/valuetransfer/address/signaturescheme/bls.go
@@ -2,14 +2,16 @@ package signaturescheme
 
 import (
 	"fmt"
-	"github.com/iotaledger/goshimmer/packages/binary/valuetransfer/address"
+	"math/rand"
+
 	"github.com/mr-tron/base58"
 	"go.dedis.ch/kyber/v3"
 	"go.dedis.ch/kyber/v3/pairing/bn256"
 	"go.dedis.ch/kyber/v3/sign"
 	"go.dedis.ch/kyber/v3/sign/bdn"
 	"go.dedis.ch/kyber/v3/util/random"
-	"math/rand"
+
+	"github.com/iotaledger/goshimmer/packages/binary/valuetransfer/address"
 )
 
 // BLS implements BLS signature scheme which is robust against rogue public key attacks, or BDN
@@ -19,7 +21,6 @@ import (
 // This package doesn't implement any threshold signature related primitives.
 // it only contains what is needed for the node to check validity of the BLS signatures against addresses
 // and also minimum signing required for testing
-
 var suite = bn256.NewSuite()
 
 const (
@@ -31,7 +32,6 @@ const (
 
 // ---------------- implements SignatureScheme interface
 // blsSignatureScheme defines an interface for the key pairs of BLS signatures.
-
 type blsSignatureScheme struct {
 	priKey kyber.Scalar
 	pubKey kyber.Point
@@ -43,7 +43,6 @@ var rnd = random.New(rand.New(rand.NewSource(42)))
 // RandBLS creates a RANDOM instance of a signature scheme, that is used to sign the corresponding address.
 // mostly intended for testing.
 // only for testing: each time same sequence!
-
 func RandBLS() SignatureScheme {
 	ret := &blsSignatureScheme{}
 	ret.priKey, ret.pubKey = bdn.NewKeyPair(suite, rnd)
@@ -52,7 +51,6 @@ func RandBLS() SignatureScheme {
 
 // BLS creates an instance of BLS signature scheme
 // from given private and public keys in marshaled binary form
-
 func BLS(priKey, pubKey []byte) (SignatureScheme, error) {
 	if len(priKey) != BLS_PRIVATE_KEY_SIZE || len(pubKey) != BLS_PUBLIC_KEY_SIZE {
 		return nil, fmt.Errorf("wrong key size")
@@ -117,7 +115,7 @@ func BLSSignatureFromBytes(data []byte) (result *blsSignature, err error, consum
 	consumedBytes = 0
 	err = nil
 	if len(data) < BLS_FULL_SIGNATURE_SIZE {
-		err = fmt.Errorf("marshalled BLS signature size must be %d", BLS_FULL_SIGNATURE_SIZE)
+		err = fmt.Errorf("marshaled BLS signature size must be %d", BLS_FULL_SIGNATURE_SIZE)
 		return
 	}
 	if data[0] != address.VERSION_BLS {
diff --git a/packages/binary/valuetransfer/address/signaturescheme/bls_test.go b/packages/binary/valuetransfer/address/signaturescheme/bls_test.go
index 28e1a3a78b508d3d304f2aa365eabeb696e44694..9e1a38aa85f917454ee5e2c84389c723884c021a 100644
--- a/packages/binary/valuetransfer/address/signaturescheme/bls_test.go
+++ b/packages/binary/valuetransfer/address/signaturescheme/bls_test.go
@@ -1,14 +1,14 @@
 package signaturescheme
 
 import (
-	"github.com/magiconair/properties/assert"
 	"testing"
+
+	"github.com/magiconair/properties/assert"
 )
 
 var dataToSign = []byte("Hello Boneh-Lynn-Shacham (BLS) --> Boneh-Drijvers-Neven (BDN)")
 
 func TestBLS_base(t *testing.T) {
-
 	blsSigScheme := RandBLS()
 	t.Logf("generating random BLS signature scheme: %s\n", blsSigScheme.(*blsSignatureScheme).String())
 	signature := blsSigScheme.Sign(dataToSign)
diff --git a/packages/binary/valuetransfer/address/signaturescheme/ed25519.go b/packages/binary/valuetransfer/address/signaturescheme/ed25519.go
index 4a3db62f31091ec1ab9d092a1c66049f586c6ca8..7da880a33a614ea44e690df9a01aed1eead95147 100644
--- a/packages/binary/valuetransfer/address/signaturescheme/ed25519.go
+++ b/packages/binary/valuetransfer/address/signaturescheme/ed25519.go
@@ -3,7 +3,8 @@ package signaturescheme
 import (
 	"fmt"
 
-	"github.com/iotaledger/goshimmer/packages/binary/marshalutil"
+	"github.com/iotaledger/hive.go/marshalutil"
+
 	"github.com/iotaledger/goshimmer/packages/binary/signature/ed25119"
 	"github.com/iotaledger/goshimmer/packages/binary/valuetransfer/address"
 )
diff --git a/packages/binary/valuetransfer/balance/balance.go b/packages/binary/valuetransfer/balance/balance.go
index e9e3acb2747efa07138ec022c85747c98d64c6fa..d969817c1ef7f4317d9f7fe2e1710c1fc24c8fc4 100644
--- a/packages/binary/valuetransfer/balance/balance.go
+++ b/packages/binary/valuetransfer/balance/balance.go
@@ -3,7 +3,7 @@ package balance
 import (
 	"strconv"
 
-	"github.com/iotaledger/goshimmer/packages/binary/marshalutil"
+	"github.com/iotaledger/hive.go/marshalutil"
 )
 
 type Balance struct {
diff --git a/packages/binary/valuetransfer/balance/color.go b/packages/binary/valuetransfer/balance/color.go
index a37941884dfc6b14402df0112d698715a4f7dde0..b50ccacfd5458773a0167a3adbdf26a279485a6c 100644
--- a/packages/binary/valuetransfer/balance/color.go
+++ b/packages/binary/valuetransfer/balance/color.go
@@ -1,9 +1,8 @@
 package balance
 
 import (
+	"github.com/iotaledger/hive.go/marshalutil"
 	"github.com/mr-tron/base58"
-
-	"github.com/iotaledger/goshimmer/packages/binary/marshalutil"
 )
 
 type Color [ColorLength]byte
diff --git a/packages/binary/valuetransfer/payload/id.go b/packages/binary/valuetransfer/payload/id.go
index 313af04e90758de12b082d06967639819845d9f8..43241a6c059da3ad23a2b68712f709ad87bfa21f 100644
--- a/packages/binary/valuetransfer/payload/id.go
+++ b/packages/binary/valuetransfer/payload/id.go
@@ -4,9 +4,8 @@ import (
 	"crypto/rand"
 	"fmt"
 
+	"github.com/iotaledger/hive.go/marshalutil"
 	"github.com/mr-tron/base58"
-
-	"github.com/iotaledger/goshimmer/packages/binary/marshalutil"
 )
 
 // Id represents the hash of a payload that is used to identify the given payload.
diff --git a/packages/binary/valuetransfer/payload/payload.go b/packages/binary/valuetransfer/payload/payload.go
index c97b2f128cc97537eedb61568b56f4a4ce1e3596..c9e6ff69f4fe5b0ede1bf6e1af2b6e14f5de565c 100644
--- a/packages/binary/valuetransfer/payload/payload.go
+++ b/packages/binary/valuetransfer/payload/payload.go
@@ -3,11 +3,11 @@ package payload
 import (
 	"sync"
 
+	"github.com/iotaledger/hive.go/marshalutil"
 	"github.com/iotaledger/hive.go/objectstorage"
 	"github.com/iotaledger/hive.go/stringify"
 	"golang.org/x/crypto/blake2b"
 
-	"github.com/iotaledger/goshimmer/packages/binary/marshalutil"
 	"github.com/iotaledger/goshimmer/packages/binary/tangle/model/message/payload"
 	"github.com/iotaledger/goshimmer/packages/binary/valuetransfer/transaction"
 )
@@ -34,15 +34,15 @@ func New(trunkPayloadId, branchPayloadId Id, valueTransfer *transaction.Transact
 	}
 }
 
-func FromStorage(key []byte) objectstorage.StorableObject {
+func StorableObjectFromKey(key []byte) (objectstorage.StorableObject, error) {
 	id, err, _ := IdFromBytes(key)
 	if err != nil {
-		panic(err)
+		return nil, err
 	}
 
 	return &Payload{
 		id: &id,
-	}
+	}, nil
 }
 
 // FromBytes parses the marshaled version of a Payload into an object.
@@ -168,10 +168,7 @@ func (payload *Payload) Bytes() (bytes []byte) {
 	}
 
 	// retrieve bytes of transfer
-	transferBytes, err := payload.Transaction().MarshalBinary()
-	if err != nil {
-		return
-	}
+	transferBytes := payload.Transaction().ObjectStorageValue()
 
 	// marshal fields
 	payloadLength := IdLength + IdLength + len(transferBytes)
@@ -202,15 +199,21 @@ func (payload *Payload) String() string {
 
 var Type = payload.Type(1)
 
-func (payload *Payload) GetType() payload.Type {
+func (payload *Payload) Type() payload.Type {
 	return Type
 }
 
-func (payload *Payload) MarshalBinary() (bytes []byte, err error) {
-	return payload.Bytes(), nil
+func (payload *Payload) ObjectStorageValue() []byte {
+	return payload.Bytes()
+}
+
+func (payload *Payload) UnmarshalObjectStorageValue(data []byte) (err error) {
+	_, err, _ = FromBytes(data, payload)
+
+	return
 }
 
-func (payload *Payload) UnmarshalBinary(data []byte) (err error) {
+func (payload *Payload) Unmarshal(data []byte) (err error) {
 	_, err, _ = FromBytes(data, payload)
 
 	return
@@ -219,7 +222,7 @@ func (payload *Payload) UnmarshalBinary(data []byte) (err error) {
 func init() {
 	payload.RegisterType(Type, func(data []byte) (payload payload.Payload, err error) {
 		payload = &Payload{}
-		err = payload.UnmarshalBinary(data)
+		err = payload.Unmarshal(data)
 
 		return
 	})
@@ -232,11 +235,11 @@ var _ payload.Payload = &Payload{}
 
 // region StorableObject implementation ////////////////////////////////////////////////////////////////////////////////
 
-// MarshalBinary() (bytes []byte, err error) already implemented by Payload
+// ObjectStorageValue() (bytes []byte, err error) already implemented by Payload
 
-// UnmarshalBinary(data []byte) (err error) already implemented by Payload
+// UnmarshalObjectStorageValue(data []byte) (err error) already implemented by Payload
 
-func (payload *Payload) GetStorageKey() []byte {
+func (payload *Payload) ObjectStorageKey() []byte {
 	id := payload.Id()
 
 	return id[:]
diff --git a/packages/binary/valuetransfer/tangle/attachment.go b/packages/binary/valuetransfer/tangle/attachment.go
index 9dcfadb462596bd48d54d50977f88ed8faf9f2ca..372d91eb8d03b78e75e92f213958be9eef7a7787 100644
--- a/packages/binary/valuetransfer/tangle/attachment.go
+++ b/packages/binary/valuetransfer/tangle/attachment.go
@@ -1,10 +1,10 @@
 package tangle
 
 import (
+	"github.com/iotaledger/hive.go/marshalutil"
 	"github.com/iotaledger/hive.go/objectstorage"
 	"github.com/iotaledger/hive.go/stringify"
 
-	"github.com/iotaledger/goshimmer/packages/binary/marshalutil"
 	"github.com/iotaledger/goshimmer/packages/binary/valuetransfer/payload"
 	"github.com/iotaledger/goshimmer/packages/binary/valuetransfer/transaction"
 )
@@ -33,7 +33,7 @@ func NewAttachment(transactionId transaction.Id, payloadId payload.Id) *Attachme
 	}
 }
 
-// AttachmentFromBytes unmarshals a MissingOutput from a sequence of bytes - it either creates a new object or fills the
+// AttachmentFromBytes unmarshals an Attachment from a sequence of bytes - it either creates a new object or fills the
 // optionally provided one with the parsed information.
 func AttachmentFromBytes(bytes []byte, optionalTargetObject ...*Attachment) (result *Attachment, err error, consumedBytes int) {
 	// determine the target object that will hold the unmarshaled information
@@ -54,20 +54,30 @@ func AttachmentFromBytes(bytes []byte, optionalTargetObject ...*Attachment) (res
 	if result.payloadId, err = payload.ParseId(marshalUtil); err != nil {
 		return
 	}
+	result.storageKey = marshalutil.New(bytes[:AttachmentLength]).Bytes(true)
 	consumedBytes = marshalUtil.ReadOffset()
 
 	return
 }
 
-// AttachmentFromStorage gets called when we restore an Attachment from the storage - it parses the key bytes and
+// Parse is a wrapper for simplified unmarshaling of Attachments from a byte stream using the marshalUtil package.
+func ParseAttachment(marshalUtil *marshalutil.MarshalUtil) (*Attachment, error) {
+	if attachment, err := marshalUtil.Parse(func(data []byte) (interface{}, error, int) { return AttachmentFromBytes(data) }); err != nil {
+		return nil, err
+	} else {
+		return attachment.(*Attachment), nil
+	}
+}
+
+// AttachmentFromStorageKey gets called when we restore an Attachment from the storage - it parses the key bytes and
 // returns the new object.
-func AttachmentFromStorage(keyBytes []byte) objectstorage.StorableObject {
+func AttachmentFromStorageKey(keyBytes []byte) (objectstorage.StorableObject, error) {
 	result, err, _ := AttachmentFromBytes(keyBytes)
 	if err != nil {
-		panic(err)
+		return nil, err
 	}
 
-	return result
+	return result, nil
 }
 
 // TransactionId returns the transaction id of this Attachment.
@@ -80,9 +90,9 @@ func (attachment *Attachment) PayloadId() payload.Id {
 	return attachment.payloadId
 }
 
-// Bytes marshals an Attachment into a sequence of bytes.
+// Bytes marshals the Attachment into a sequence of bytes.
 func (attachment *Attachment) Bytes() []byte {
-	return attachment.GetStorageKey()
+	return attachment.ObjectStorageKey()
 }
 
 // String returns a human readable version of the Attachment.
@@ -93,20 +103,20 @@ func (attachment *Attachment) String() string {
 	)
 }
 
-// GetStorageKey returns the key that is used to store the object in the database.
-func (attachment *Attachment) GetStorageKey() []byte {
+// ObjectStorageKey returns the key that is used to store the object in the database.
+func (attachment *Attachment) ObjectStorageKey() []byte {
 	return attachment.storageKey
 }
 
-// MarshalBinary marshals the "content part" of an Attachment to a sequence of bytes. Since all of the information for
-// this object are stored in its key, this method does nothing and is only required to conform with the interface.
-func (attachment *Attachment) MarshalBinary() (data []byte, err error) {
+// ObjectStorageValue marshals the "content part" of an Attachment to a sequence of bytes. Since all of the information
+// for this object are stored in its key, this method does nothing and is only required to conform with the interface.
+func (attachment *Attachment) ObjectStorageValue() (data []byte) {
 	return
 }
 
-// UnmarshalBinary unmarshals the "content part" of an Attachment from a sequence of bytes. Since all of the information
+// UnmarshalObjectStorageValue unmarshals the "content part" of an Attachment from a sequence of bytes. Since all of the information
 // for this object are stored in its key, this method does nothing and is only required to conform with the interface.
-func (attachment *Attachment) UnmarshalBinary(data []byte) (err error) {
+func (attachment *Attachment) UnmarshalObjectStorageValue(data []byte) (err error) {
 	return
 }
 
diff --git a/packages/binary/valuetransfer/tangle/consumer.go b/packages/binary/valuetransfer/tangle/consumer.go
new file mode 100644
index 0000000000000000000000000000000000000000..e0a41212672f16dcc9e4a3f5bcf4f617d88eca92
--- /dev/null
+++ b/packages/binary/valuetransfer/tangle/consumer.go
@@ -0,0 +1,131 @@
+package tangle
+
+import (
+	"github.com/iotaledger/hive.go/marshalutil"
+	"github.com/iotaledger/hive.go/objectstorage"
+	"github.com/iotaledger/hive.go/stringify"
+
+	"github.com/iotaledger/goshimmer/packages/binary/valuetransfer/transaction"
+)
+
+// Consumer stores the information which transaction output was consumed by which transaction. We need this to be able
+// to perform reverse lookups from transaction outputs to their corresponding consuming transactions.
+type Consumer struct {
+	objectstorage.StorableObjectFlags
+
+	consumedInput transaction.OutputId
+	transactionId transaction.Id
+
+	storageKey []byte
+}
+
+// NewConsumer creates a Consumer object with the given information.
+func NewConsumer(consumedInput transaction.OutputId, transactionId transaction.Id) *Consumer {
+	return &Consumer{
+		consumedInput: consumedInput,
+		transactionId: transactionId,
+
+		storageKey: marshalutil.New(ConsumerLength).
+			WriteBytes(consumedInput.Bytes()).
+			WriteBytes(transactionId.Bytes()).
+			Bytes(),
+	}
+}
+
+// ConsumerFromBytes unmarshals a Consumer from a sequence of bytes - it either creates a new object or fills the
+// optionally provided one with the parsed information.
+func ConsumerFromBytes(bytes []byte, optionalTargetObject ...*Consumer) (result *Consumer, err error, consumedBytes int) {
+	// determine the target object that will hold the unmarshaled information
+	switch len(optionalTargetObject) {
+	case 0:
+		result = &Consumer{}
+	case 1:
+		result = optionalTargetObject[0]
+	default:
+		panic("too many arguments in call to ConsumerFromBytes")
+	}
+
+	// parse the bytes
+	marshalUtil := marshalutil.New(bytes)
+	if result.consumedInput, err = transaction.ParseOutputId(marshalUtil); err != nil {
+		return
+	}
+	if result.transactionId, err = transaction.ParseId(marshalUtil); err != nil {
+		return
+	}
+	result.storageKey = marshalutil.New(bytes[:ConsumerLength]).Bytes(true)
+	consumedBytes = marshalUtil.ReadOffset()
+
+	return
+}
+
+// Parse is a wrapper for simplified unmarshaling of Consumers from a byte stream using the marshalUtil package.
+func ParseConsumer(marshalUtil *marshalutil.MarshalUtil) (*Consumer, error) {
+	if consumer, err := marshalUtil.Parse(func(data []byte) (interface{}, error, int) { return ConsumerFromBytes(data) }); err != nil {
+		return nil, err
+	} else {
+		return consumer.(*Consumer), nil
+	}
+}
+
+// ConsumerFromStorage gets called when we restore an Consumer from the storage - it parses the key bytes and
+// returns the new object.
+func ConsumerFromStorage(keyBytes []byte) objectstorage.StorableObject {
+	result, err, _ := ConsumerFromBytes(keyBytes)
+	if err != nil {
+		panic(err)
+	}
+
+	return result
+}
+
+// ConsumedInput returns the OutputId of the Consumer.
+func (consumer *Consumer) ConsumedInput() transaction.OutputId {
+	return consumer.consumedInput
+}
+
+// TransactionId returns the transaction Id of this Consumer.
+func (consumer *Consumer) TransactionId() transaction.Id {
+	return consumer.transactionId
+}
+
+// Bytes marshals the Consumer into a sequence of bytes.
+func (consumer *Consumer) Bytes() []byte {
+	return consumer.ObjectStorageKey()
+}
+
+// String returns a human readable version of the Consumer.
+func (consumer *Consumer) String() string {
+	return stringify.Struct("Consumer",
+		stringify.StructField("consumedInput", consumer.ConsumedInput()),
+		stringify.StructField("transactionId", consumer.TransactionId()),
+	)
+}
+
+// ObjectStorageKey returns the key that is used to store the object in the database.
+func (consumer *Consumer) ObjectStorageKey() []byte {
+	return consumer.storageKey
+}
+
+// ObjectStorageValue marshals the "content part" of an Consumer to a sequence of bytes. Since all of the information for
+// this object are stored in its key, this method does nothing and is only required to conform with the interface.
+func (consumer *Consumer) ObjectStorageValue() (data []byte) {
+	return
+}
+
+// UnmarshalObjectStorageValue unmarshals the "content part" of a Consumer from a sequence of bytes. Since all of the information
+// for this object are stored in its key, this method does nothing and is only required to conform with the interface.
+func (consumer *Consumer) UnmarshalObjectStorageValue(data []byte) (err error) {
+	return
+}
+
+// Update is disabled - updates are supposed to happen through the setters (if existing).
+func (consumer *Consumer) Update(other objectstorage.StorableObject) {
+	panic("update forbidden")
+}
+
+// Interface contract: make compiler warn if the interface is not implemented correctly.
+var _ objectstorage.StorableObject = &Consumer{}
+
+// ConsumerLength holds the length of a marshaled Consumer in bytes.
+const ConsumerLength = transaction.OutputIdLength + transaction.IdLength
diff --git a/packages/binary/valuetransfer/tangle/events.go b/packages/binary/valuetransfer/tangle/events.go
index 15e31ddd8348f6af855e3d711fd1a924e46c2797..f36280cb9dca449d2b6ad47163741d60064ad766 100644
--- a/packages/binary/valuetransfer/tangle/events.go
+++ b/packages/binary/valuetransfer/tangle/events.go
@@ -16,6 +16,8 @@ type Events struct {
 	PayloadUnsolidifiable  *events.Event
 	TransactionRemoved     *events.Event
 	OutputMissing          *events.Event
+
+	TransactionSolid *events.Event
 }
 
 func newEvents() *Events {
@@ -25,8 +27,9 @@ func newEvents() *Events {
 		MissingPayloadReceived: events.NewEvent(cachedPayloadEvent),
 		PayloadMissing:         events.NewEvent(payloadIdEvent),
 		PayloadUnsolidifiable:  events.NewEvent(payloadIdEvent),
-		TransactionRemoved:     events.NewEvent(payloadIdEvent),
 		OutputMissing:          events.NewEvent(outputIdEvent),
+
+		TransactionSolid: events.NewEvent(transactionEvent),
 	}
 }
 
@@ -41,6 +44,13 @@ func cachedPayloadEvent(handler interface{}, params ...interface{}) {
 	)
 }
 
+func transactionEvent(handler interface{}, params ...interface{}) {
+	handler.(func(*transaction.Transaction, *CachedTransactionMetadata))(
+		params[0].(*transaction.Transaction),
+		params[1].(*CachedTransactionMetadata).Retain(),
+	)
+}
+
 func outputIdEvent(handler interface{}, params ...interface{}) {
 	handler.(func(transaction.OutputId))(params[0].(transaction.OutputId))
 }
diff --git a/packages/binary/valuetransfer/tangle/missingoutput.go b/packages/binary/valuetransfer/tangle/missingoutput.go
index 92b34c383995a0127d5b19f2775630102f4d4633..628d4a68e0aa57b59f9fc173be9bf44175400112 100644
--- a/packages/binary/valuetransfer/tangle/missingoutput.go
+++ b/packages/binary/valuetransfer/tangle/missingoutput.go
@@ -3,9 +3,9 @@ package tangle
 import (
 	"time"
 
+	"github.com/iotaledger/hive.go/marshalutil"
 	"github.com/iotaledger/hive.go/objectstorage"
 
-	"github.com/iotaledger/goshimmer/packages/binary/marshalutil"
 	"github.com/iotaledger/goshimmer/packages/binary/valuetransfer/transaction"
 )
 
@@ -51,9 +51,9 @@ func MissingOutputFromBytes(bytes []byte, optionalTargetObject ...*MissingOutput
 	return
 }
 
-// MissingOutputFromStorage gets called when we restore a MissingOutput from the storage. The content will be
-// unmarshaled by an external caller using the binary.MarshalBinary interface.
-func MissingOutputFromStorage(keyBytes []byte) objectstorage.StorableObject {
+// MissingOutputFromStorageKey gets called when we restore a MissingOutput from the storage. The content will be
+// unmarshaled by an external caller using the binary.ObjectStorageValue interface.
+func MissingOutputFromStorageKey(keyBytes []byte) (objectstorage.StorableObject, error) {
 	outputId, err, _ := transaction.OutputIdFromBytes(keyBytes)
 	if err != nil {
 		panic(err)
@@ -61,7 +61,7 @@ func MissingOutputFromStorage(keyBytes []byte) objectstorage.StorableObject {
 
 	return &MissingOutput{
 		outputId: outputId,
-	}
+	}, nil
 }
 
 // Id returns the id of the Output that is missing.
@@ -84,26 +84,29 @@ func (missingOutput *MissingOutput) Bytes() []byte {
 	return marshalUtil.Bytes()
 }
 
-// GetStorageKey returns the key that is used to store the object in the object storage.
-func (missingOutput *MissingOutput) GetStorageKey() []byte {
+// ObjectStorageKey returns the key that is used to store the object in the object storage.
+func (missingOutput *MissingOutput) ObjectStorageKey() []byte {
 	return missingOutput.outputId.Bytes()
 }
 
-// Update is disabled and panics if it ever gets called - updates are supposed to happen through the setters.
-func (missingOutput *MissingOutput) Update(other objectstorage.StorableObject) {
-	panic("implement me")
-}
-
-// MarshalBinary returns a bytes representation of the Transaction by implementing the encoding.BinaryMarshaler
+// ObjectStorageValue returns a bytes representation of the Transaction by implementing the encoding.BinaryMarshaler
 // interface.
-func (missingOutput *MissingOutput) MarshalBinary() (data []byte, err error) {
-	return missingOutput.Bytes(), nil
+func (missingOutput *MissingOutput) ObjectStorageValue() []byte {
+	return missingOutput.Bytes()
 }
 
-// UnmarshalBinary restores the values of a MissingOutput from a sequence of bytes using the  encoding.BinaryUnmarshaler
+// UnmarshalObjectStorageValue restores the values of a MissingOutput from a sequence of bytes using the  encoding.BinaryUnmarshaler
 // interface.
-func (missingOutput *MissingOutput) UnmarshalBinary(data []byte) (err error) {
+func (missingOutput *MissingOutput) UnmarshalObjectStorageValue(data []byte) (err error) {
 	_, err, _ = MissingOutputFromBytes(data, missingOutput)
 
 	return
 }
+
+// Update is disabled and panics if it ever gets called - updates are supposed to happen through the setters.
+func (missingOutput *MissingOutput) Update(other objectstorage.StorableObject) {
+	panic("implement me")
+}
+
+// Interface contract: make compiler warn if the interface is not implemented correctly.
+var _ objectstorage.StorableObject = &MissingOutput{}
diff --git a/packages/binary/valuetransfer/tangle/missingpayload.go b/packages/binary/valuetransfer/tangle/missingpayload.go
index c4eb653276ad39e4697adfca578e3d73a6d97496..527147538538686db202c6a3bc07d9ccd3ad0196 100644
--- a/packages/binary/valuetransfer/tangle/missingpayload.go
+++ b/packages/binary/valuetransfer/tangle/missingpayload.go
@@ -3,9 +3,9 @@ package tangle
 import (
 	"time"
 
+	"github.com/iotaledger/hive.go/marshalutil"
 	"github.com/iotaledger/hive.go/objectstorage"
 
-	"github.com/iotaledger/goshimmer/packages/binary/marshalutil"
 	"github.com/iotaledger/goshimmer/packages/binary/valuetransfer/payload"
 )
 
@@ -52,10 +52,10 @@ func MissingPayloadFromBytes(bytes []byte, optionalTargetObject ...*MissingPaylo
 	return
 }
 
-// MissingPayloadFromStorage gets called when we restore an entry for a missing value transfer payload from the storage. The bytes and
-// the content will be unmarshaled by an external caller using the binary.MarshalBinary interface.
-func MissingPayloadFromStorage([]byte) objectstorage.StorableObject {
-	return &MissingPayload{}
+// MissingPayloadFromStorageKey gets called when we restore an entry for a missing value transfer payload from the storage. The bytes and
+// the content will be unmarshaled by an external caller using the binary.ObjectStorageValue interface.
+func MissingPayloadFromStorageKey([]byte) (objectstorage.StorableObject, error) {
+	return &MissingPayload{}, nil
 }
 
 // GetId returns the payload id, that is missing.
@@ -78,26 +78,29 @@ func (missingPayload *MissingPayload) Bytes() []byte {
 	return marshalUtil.Bytes()
 }
 
-// GetStorageKey returns the key that is used to store the object in the database.
-// It is required to match StorableObject interface.
-func (missingPayload *MissingPayload) GetStorageKey() []byte {
-	return missingPayload.payloadId.Bytes()
-}
-
 // Update is disabled and panics if it ever gets called - updates are supposed to happen through the setters.
 // It is required to match StorableObject interface.
 func (missingPayload *MissingPayload) Update(other objectstorage.StorableObject) {
 	panic("implement me")
 }
 
-// MarshalBinary is required to match the encoding.BinaryMarshaler interface.
-func (missingPayload *MissingPayload) MarshalBinary() (data []byte, err error) {
-	return missingPayload.Bytes(), nil
+// ObjectStorageKey returns the key that is used to store the object in the database.
+// It is required to match StorableObject interface.
+func (missingPayload *MissingPayload) ObjectStorageKey() []byte {
+	return missingPayload.payloadId.Bytes()
+}
+
+// ObjectStorageValue is required to match the encoding.BinaryMarshaler interface.
+func (missingPayload *MissingPayload) ObjectStorageValue() (data []byte) {
+	return missingPayload.Bytes()
 }
 
-// UnmarshalBinary is required to match the encoding.BinaryUnmarshaler interface.
-func (missingPayload *MissingPayload) UnmarshalBinary(data []byte) (err error) {
+// UnmarshalObjectStorageValue is required to match the encoding.BinaryUnmarshaler interface.
+func (missingPayload *MissingPayload) UnmarshalObjectStorageValue(data []byte) (err error) {
 	_, err, _ = MissingPayloadFromBytes(data, missingPayload)
 
 	return
 }
+
+// Interface contract: make compiler warn if the interface is not implemented correctly.
+var _ objectstorage.StorableObject = &MissingPayload{}
diff --git a/packages/binary/valuetransfer/tangle/payloadapprover.go b/packages/binary/valuetransfer/tangle/payloadapprover.go
index e86379258ed67159df15b2e40d10313d5b2ec9a4..f0b34f1d413b739d683d1ddd9af34f1439d5e8f8 100644
--- a/packages/binary/valuetransfer/tangle/payloadapprover.go
+++ b/packages/binary/valuetransfer/tangle/payloadapprover.go
@@ -1,9 +1,9 @@
 package tangle
 
 import (
+	"github.com/iotaledger/hive.go/marshalutil"
 	"github.com/iotaledger/hive.go/objectstorage"
 
-	"github.com/iotaledger/goshimmer/packages/binary/marshalutil"
 	"github.com/iotaledger/goshimmer/packages/binary/valuetransfer/payload"
 )
 
@@ -31,19 +31,19 @@ func NewPayloadApprover(referencedPayload payload.Id, approvingPayload payload.I
 	}
 }
 
-// PayloadApproverFromStorage get's called when we restore transaction metadata from the storage.
-// In contrast to other database models, it unmarshals the information from the key and does not use the UnmarshalBinary
+// PayloadApproverFromStorageKey get's called when we restore transaction metadata from the storage.
+// In contrast to other database models, it unmarshals the information from the key and does not use the UnmarshalObjectStorageValue
 // method.
-func PayloadApproverFromStorage(idBytes []byte) objectstorage.StorableObject {
+func PayloadApproverFromStorageKey(idBytes []byte) (objectstorage.StorableObject, error) {
 	marshalUtil := marshalutil.New(idBytes)
 
 	referencedPayloadId, err := payload.ParseId(marshalUtil)
 	if err != nil {
-		panic(err)
+		return nil, err
 	}
 	approvingPayloadId, err := payload.ParseId(marshalUtil)
 	if err != nil {
-		panic(err)
+		return nil, err
 	}
 
 	result := &PayloadApprover{
@@ -52,7 +52,7 @@ func PayloadApproverFromStorage(idBytes []byte) objectstorage.StorableObject {
 		storageKey:          marshalUtil.Bytes(true),
 	}
 
-	return result
+	return result, nil
 }
 
 // GetApprovingPayloadId returns the id of the approving payload.
@@ -60,21 +60,21 @@ func (payloadApprover *PayloadApprover) GetApprovingPayloadId() payload.Id {
 	return payloadApprover.approvingPayloadId
 }
 
-// GetStorageKey returns the key that is used to store the object in the database.
+// ObjectStorageKey returns the key that is used to store the object in the database.
 // It is required to match StorableObject interface.
-func (payloadApprover *PayloadApprover) GetStorageKey() []byte {
+func (payloadApprover *PayloadApprover) ObjectStorageKey() []byte {
 	return payloadApprover.storageKey
 }
 
-// MarshalBinary is implemented to conform with the StorableObject interface, but it does not really do anything,
+// ObjectStorageValue is implemented to conform with the StorableObject interface, but it does not really do anything,
 // since all of the information about an approver are stored in the "key".
-func (payloadApprover *PayloadApprover) MarshalBinary() (data []byte, err error) {
+func (payloadApprover *PayloadApprover) ObjectStorageValue() (data []byte) {
 	return
 }
 
-// UnmarshalBinary is implemented to conform with the StorableObject interface, but it does not really do anything,
-// since all of the information about an approver are stored in the "key".
-func (payloadApprover *PayloadApprover) UnmarshalBinary(data []byte) error {
+// UnmarshalObjectStorageValue is implemented to conform with the StorableObject interface, but it does not really do
+// anything, since all of the information about an approver are stored in the "key".
+func (payloadApprover *PayloadApprover) UnmarshalObjectStorageValue(data []byte) error {
 	return nil
 }
 
diff --git a/packages/binary/valuetransfer/tangle/payloadmetadata.go b/packages/binary/valuetransfer/tangle/payloadmetadata.go
index d693c86ef09f99f746aff937840be6c690709219..a73dec84367a85686d38cfa2c122ccfe43cbb197 100644
--- a/packages/binary/valuetransfer/tangle/payloadmetadata.go
+++ b/packages/binary/valuetransfer/tangle/payloadmetadata.go
@@ -4,10 +4,10 @@ import (
 	"sync"
 	"time"
 
+	"github.com/iotaledger/hive.go/marshalutil"
 	"github.com/iotaledger/hive.go/objectstorage"
 	"github.com/iotaledger/hive.go/stringify"
 
-	"github.com/iotaledger/goshimmer/packages/binary/marshalutil"
 	"github.com/iotaledger/goshimmer/packages/binary/valuetransfer/payload"
 )
 
@@ -60,17 +60,17 @@ func PayloadMetadataFromBytes(bytes []byte, optionalTargetObject ...*PayloadMeta
 	return
 }
 
-// PayloadMetadataFromStorage gets called when we restore transaction metadata from the storage. The bytes and the content will be
-// unmarshaled by an external caller using the binary.MarshalBinary interface.
-func PayloadMetadataFromStorage(id []byte) objectstorage.StorableObject {
+// PayloadMetadataFromStorageKey gets called when we restore transaction metadata from the storage. The bytes and the content will be
+// unmarshaled by an external caller using the binary.ObjectStorageValue interface.
+func PayloadMetadataFromStorageKey(id []byte) (objectstorage.StorableObject, error) {
 	result := &PayloadMetadata{}
 
 	var err error
 	if result.payloadId, err = payload.ParseId(marshalutil.New(id)); err != nil {
-		panic(err)
+		return nil, err
 	}
 
-	return result
+	return result, nil
 }
 
 // ParsePayloadMetadata is a wrapper for simplified unmarshaling in a byte stream using the marshalUtil package.
@@ -153,9 +153,9 @@ func (payloadMetadata *PayloadMetadata) String() string {
 	)
 }
 
-// GetStorageKey returns the key that is used to store the object in the database.
+// ObjectStorageKey returns the key that is used to store the object in the database.
 // It is required to match StorableObject interface.
-func (payloadMetadata *PayloadMetadata) GetStorageKey() []byte {
+func (payloadMetadata *PayloadMetadata) ObjectStorageKey() []byte {
 	return payloadMetadata.payloadId.Bytes()
 }
 
@@ -165,13 +165,13 @@ func (payloadMetadata *PayloadMetadata) Update(other objectstorage.StorableObjec
 	panic("update forbidden")
 }
 
-// MarshalBinary is required to match the encoding.BinaryMarshaler interface.
-func (payloadMetadata *PayloadMetadata) MarshalBinary() ([]byte, error) {
-	return payloadMetadata.Bytes(), nil
+// ObjectStorageValue is required to match the encoding.BinaryMarshaler interface.
+func (payloadMetadata *PayloadMetadata) ObjectStorageValue() []byte {
+	return payloadMetadata.Bytes()
 }
 
-// UnmarshalBinary is required to match the encoding.BinaryUnmarshaler interface.
-func (payloadMetadata *PayloadMetadata) UnmarshalBinary(data []byte) (err error) {
+// UnmarshalObjectStorageValue is required to match the encoding.BinaryUnmarshaler interface.
+func (payloadMetadata *PayloadMetadata) UnmarshalObjectStorageValue(data []byte) (err error) {
 	_, err, _ = PayloadMetadataFromBytes(data, payloadMetadata)
 
 	return
diff --git a/packages/binary/valuetransfer/tangle/tangle.go b/packages/binary/valuetransfer/tangle/tangle.go
index 5c61b2b713d39b43e8e6d1b9de471e3bcd7de928..bea66a480481a8ac931c68b0c4b2e58b9de15274 100644
--- a/packages/binary/valuetransfer/tangle/tangle.go
+++ b/packages/binary/valuetransfer/tangle/tangle.go
@@ -2,7 +2,6 @@ package tangle
 
 import (
 	"container/list"
-	"fmt"
 	"time"
 
 	"github.com/dgraph-io/badger/v2"
@@ -23,7 +22,9 @@ type Tangle struct {
 	payloadMetadataStorage *objectstorage.ObjectStorage
 	approverStorage        *objectstorage.ObjectStorage
 	missingPayloadStorage  *objectstorage.ObjectStorage
+	attachmentStorage      *objectstorage.ObjectStorage
 
+	consumerStorage                  *objectstorage.ObjectStorage
 	transactionOutputMetadataStorage *objectstorage.ObjectStorage
 	missingOutputStorage             *objectstorage.ObjectStorage
 
@@ -38,13 +39,20 @@ func New(badgerInstance *badger.DB, storageId []byte) (result *Tangle) {
 	result = &Tangle{
 		storageId: storageId,
 
-		payloadStorage:         objectstorage.New(badgerInstance, append(storageId, storageprefix.ValueTransferPayload...), payload.FromStorage, objectstorage.CacheTime(time.Second)),
-		payloadMetadataStorage: objectstorage.New(badgerInstance, append(storageId, storageprefix.ValueTransferPayloadMetadata...), PayloadMetadataFromStorage, objectstorage.CacheTime(time.Second)),
-		approverStorage:        objectstorage.New(badgerInstance, append(storageId, storageprefix.ValueTransferApprover...), PayloadApproverFromStorage, objectstorage.CacheTime(time.Second), objectstorage.PartitionKey(payload.IdLength, payload.IdLength), objectstorage.KeysOnly(true)),
-		missingPayloadStorage:  objectstorage.New(badgerInstance, append(storageId, storageprefix.ValueTransferMissingPayload...), MissingPayloadFromStorage, objectstorage.CacheTime(time.Second)),
+		// payload related storage
+		payloadStorage:         objectstorage.New(badgerInstance, append(storageId, storageprefix.ValueTransferPayload...), payload.StorableObjectFromKey, objectstorage.CacheTime(time.Second)),
+		payloadMetadataStorage: objectstorage.New(badgerInstance, append(storageId, storageprefix.ValueTransferPayloadMetadata...), PayloadMetadataFromStorageKey, objectstorage.CacheTime(time.Second)),
+		missingPayloadStorage:  objectstorage.New(badgerInstance, append(storageId, storageprefix.ValueTransferMissingPayload...), MissingPayloadFromStorageKey, objectstorage.CacheTime(time.Second)),
+		approverStorage:        objectstorage.New(badgerInstance, append(storageId, storageprefix.ValueTransferApprover...), PayloadApproverFromStorageKey, objectstorage.CacheTime(time.Second), objectstorage.PartitionKey(payload.IdLength, payload.IdLength), objectstorage.KeysOnly(true)),
 
-		transactionOutputMetadataStorage: objectstorage.New(badgerInstance, append(storageId, storageprefix.TangleApprovers...), transaction.OutputFromStorage, objectstorage.CacheTime(time.Second)),
-		missingOutputStorage:             objectstorage.New(badgerInstance, append(storageId, storageprefix.ValueTransferMissingPayload...), MissingOutputFromStorage, objectstorage.CacheTime(time.Second)),
+		// transaction related storage
+		transactionOutputMetadataStorage: objectstorage.New(badgerInstance, append(storageId, storageprefix.TangleApprovers...), transaction.OutputFromStorageKey, objectstorage.CacheTime(time.Second)),
+		missingOutputStorage:             objectstorage.New(badgerInstance, append(storageId, storageprefix.ValueTransferMissingPayload...), MissingOutputFromStorageKey, objectstorage.CacheTime(time.Second)),
+		consumerStorage:                  objectstorage.New(badgerInstance, append(storageId, storageprefix.ValueTransferConsumer...), transaction.OutputFromStorageKey, objectstorage.CacheTime(time.Second)),
+
+		attachmentStorage: objectstorage.New(badgerInstance, append(storageId, storageprefix.ValueTransferAttachment...), AttachmentFromStorageKey, objectstorage.CacheTime(time.Second)),
+
+		// transaction related storage
 
 		Events: *newEvents(),
 	}
@@ -67,6 +75,11 @@ func (tangle *Tangle) GetPayloadMetadata(payloadId payload.Id) *CachedPayloadMet
 	return &CachedPayloadMetadata{CachedObject: tangle.payloadMetadataStorage.Load(payloadId.Bytes())}
 }
 
+// GetPayloadMetadata retrieves the metadata of a value payload from the object storage.
+func (tangle *Tangle) GetTransactionMetadata(transactionId transaction.Id) *CachedTransactionMetadata {
+	return &CachedTransactionMetadata{CachedObject: tangle.missingOutputStorage.Load(transactionId.Bytes())}
+}
+
 // GetApprovers retrieves the approvers of a payload from the object storage.
 func (tangle *Tangle) GetApprovers(transactionId payload.Id) CachedApprovers {
 	approvers := make(CachedApprovers, 0)
@@ -123,21 +136,6 @@ func (tangle *Tangle) storePayloadWorker(payloadToStore *payload.Payload) {
 	payloadId := payloadToStore.Id()
 	cachedMetadata := &CachedPayloadMetadata{CachedObject: tangle.payloadMetadataStorage.Store(NewPayloadMetadata(payloadId))}
 
-	// store trunk approver
-	trunkId := payloadToStore.TrunkId()
-	tangle.approverStorage.Store(NewPayloadApprover(trunkId, payloadId)).Release()
-
-	// store branch approver
-	if branchId := payloadToStore.BranchId(); branchId != trunkId {
-		tangle.approverStorage.Store(NewPayloadApprover(branchId, trunkId)).Release()
-	}
-
-	// trigger events
-	if tangle.missingPayloadStorage.DeleteIfPresent(payloadId.Bytes()) {
-		tangle.Events.MissingPayloadReceived.Trigger(cachedPayload, cachedMetadata)
-	}
-	tangle.Events.PayloadAttached.Trigger(cachedPayload, cachedMetadata)
-
 	// retrieve or store TransactionMetadata
 	newTransaction := false
 	transactionId := cachedPayload.Unwrap().Transaction().Id()
@@ -151,11 +149,33 @@ func (tangle *Tangle) storePayloadWorker(payloadToStore *payload.Payload) {
 		return result
 	})}
 
-	// if the transaction is new, store the Consumers.
+	// store trunk approver
+	trunkId := payloadToStore.TrunkId()
+	tangle.approverStorage.Store(NewPayloadApprover(trunkId, payloadId)).Release()
+
+	// store branch approver
+	if branchId := payloadToStore.BranchId(); branchId != trunkId {
+		tangle.approverStorage.Store(NewPayloadApprover(branchId, trunkId)).Release()
+	}
+
+	// store the consumers, the first time we see a Transaction
 	if newTransaction {
-		fmt.Println("git aWADD")
+		payloadToStore.Transaction().Inputs().ForEach(func(outputId transaction.OutputId) bool {
+			tangle.consumerStorage.Store(NewConsumer(outputId, transactionId))
+
+			return true
+		})
 	}
 
+	// store attachment
+	tangle.attachmentStorage.StoreIfAbsent(NewAttachment(payloadToStore.Transaction().Id(), payloadToStore.Id()))
+
+	// trigger events
+	if tangle.missingPayloadStorage.DeleteIfPresent(payloadId.Bytes()) {
+		tangle.Events.MissingPayloadReceived.Trigger(cachedPayload, cachedMetadata)
+	}
+	tangle.Events.PayloadAttached.Trigger(cachedPayload, cachedMetadata)
+
 	// check solidity
 	tangle.solidifierWorkerPool.Submit(func() {
 		tangle.solidifyTransactionWorker(cachedPayload, cachedMetadata, cachedTransactionMetadata)
@@ -164,53 +184,73 @@ func (tangle *Tangle) storePayloadWorker(payloadToStore *payload.Payload) {
 
 // solidifyTransactionWorker is the worker function that solidifies the payloads (recursively from past to present).
 func (tangle *Tangle) solidifyTransactionWorker(cachedPayload *payload.CachedPayload, cachedMetadata *CachedPayloadMetadata, cachedTransactionMetadata *CachedTransactionMetadata) {
-	popElementsFromStack := func(stack *list.List) (*payload.CachedPayload, *CachedPayloadMetadata) {
+	popElementsFromStack := func(stack *list.List) (*payload.CachedPayload, *CachedPayloadMetadata, *CachedTransactionMetadata) {
 		currentSolidificationEntry := stack.Front()
-		currentCachedPayload := currentSolidificationEntry.Value.([2]interface{})[0]
-		currentCachedMetadata := currentSolidificationEntry.Value.([2]interface{})[1]
+		currentCachedPayload := currentSolidificationEntry.Value.([3]interface{})[0]
+		currentCachedMetadata := currentSolidificationEntry.Value.([3]interface{})[1]
+		currentCachedTransactionMetadata := currentSolidificationEntry.Value.([3]interface{})[2]
 		stack.Remove(currentSolidificationEntry)
 
-		return currentCachedPayload.(*payload.CachedPayload), currentCachedMetadata.(*CachedPayloadMetadata)
+		return currentCachedPayload.(*payload.CachedPayload), currentCachedMetadata.(*CachedPayloadMetadata), currentCachedTransactionMetadata.(*CachedTransactionMetadata)
 	}
 
 	// initialize the stack
 	solidificationStack := list.New()
-	solidificationStack.PushBack([2]interface{}{cachedPayload, cachedMetadata})
+	solidificationStack.PushBack([3]interface{}{cachedPayload, cachedMetadata, cachedTransactionMetadata})
 
 	// process payloads that are supposed to be checked for solidity recursively
 	for solidificationStack.Len() > 0 {
-		currentCachedPayload, currentCachedMetadata := popElementsFromStack(solidificationStack)
+		currentCachedPayload, currentCachedMetadata, currentCachedTransactionMetadata := popElementsFromStack(solidificationStack)
 
 		currentPayload := currentCachedPayload.Unwrap()
-		currentMetadata := currentCachedMetadata.Unwrap()
-		if currentPayload == nil || currentMetadata == nil {
+		currentPayloadMetadata := currentCachedMetadata.Unwrap()
+		currentTransaction := currentPayload.Transaction()
+		currentTransactionMetadata := currentCachedTransactionMetadata.Unwrap()
+		if currentPayload == nil || currentPayloadMetadata == nil || currentTransactionMetadata == nil {
 			currentCachedPayload.Release()
 			currentCachedMetadata.Release()
-			cachedTransactionMetadata.Release()
+			currentCachedTransactionMetadata.Release()
 
 			continue
 		}
 
-		// if current transaction is solid and was not marked as solid before: mark as solid and propagate
-		if tangle.isPayloadSolid(currentPayload, currentMetadata) && tangle.isTransactionSolid(currentPayload.Transaction(), cachedTransactionMetadata.Unwrap()) {
-			if currentMetadata.SetSolid(true) {
+		// if current transaction and payload are solid ...
+		if tangle.isPayloadSolid(currentPayload, currentPayloadMetadata) && tangle.isTransactionSolid(currentTransaction, currentTransactionMetadata) {
+			payloadBecameSolid := currentPayloadMetadata.SetSolid(true)
+			transactionBecameSolid := currentTransactionMetadata.SetSolid(true)
+
+			// if payload was marked as solid the first time ...
+			if payloadBecameSolid {
 				tangle.Events.PayloadSolid.Trigger(currentCachedPayload, currentCachedMetadata)
 
 				tangle.GetApprovers(currentPayload.Id()).Consume(func(approver *PayloadApprover) {
-					approverTransactionId := approver.GetApprovingPayloadId()
-
-					solidificationStack.PushBack([2]interface{}{
-						tangle.GetPayload(approverTransactionId),
-						tangle.GetPayloadMetadata(approverTransactionId),
+					approvingPayloadId := approver.GetApprovingPayloadId()
+					approvingCachedPayload := tangle.GetPayload(approvingPayloadId)
+
+					approvingCachedPayload.Consume(func(payload *payload.Payload) {
+						solidificationStack.PushBack([3]interface{}{
+							approvingCachedPayload,
+							tangle.GetPayloadMetadata(approvingPayloadId),
+							tangle.GetTransactionMetadata(payload.Transaction().Id()),
+						})
 					})
 				})
 			}
+
+			if transactionBecameSolid {
+				tangle.Events.TransactionSolid.Trigger(currentTransaction, currentTransactionMetadata)
+
+				currentTransaction.Inputs().ForEach(func(outputId transaction.OutputId) bool {
+					return true
+				})
+				//tangle.GetConsumers(outputId)
+			}
 		}
 
-		// release cached results
+		// release cached objects
 		currentCachedPayload.Release()
 		currentCachedMetadata.Release()
-		cachedTransactionMetadata.Release()
+		currentCachedTransactionMetadata.Release()
 	}
 }
 
diff --git a/packages/binary/valuetransfer/tangle/transactionmetadata.go b/packages/binary/valuetransfer/tangle/transactionmetadata.go
index 898c57a7002705de783894a1cd0a2b915d2c4ef8..a920bce1c806b8f5ed2de036bb62e89853e8d7c9 100644
--- a/packages/binary/valuetransfer/tangle/transactionmetadata.go
+++ b/packages/binary/valuetransfer/tangle/transactionmetadata.go
@@ -4,10 +4,10 @@ import (
 	"sync"
 	"time"
 
+	"github.com/iotaledger/hive.go/marshalutil"
 	"github.com/iotaledger/hive.go/objectstorage"
 	"github.com/iotaledger/hive.go/stringify"
 
-	"github.com/iotaledger/goshimmer/packages/binary/marshalutil"
 	"github.com/iotaledger/goshimmer/packages/binary/valuetransfer/transaction"
 )
 
@@ -61,7 +61,7 @@ func TransactionMetadataFromBytes(bytes []byte, optionalTargetObject ...*Transac
 }
 
 // TransactionMetadataFromStorage is the factory method for TransactionMetadata objects stored in the objectstorage. The bytes and the content
-// will be filled by the objectstorage, by subsequently calling MarshalBinary.
+// will be filled by the objectstorage, by subsequently calling ObjectStorageValue.
 func TransactionMetadataFromStorage(storageKey []byte) objectstorage.StorableObject {
 	result := &TransactionMetadata{}
 
@@ -153,8 +153,8 @@ func (transactionMetadata *TransactionMetadata) String() string {
 	)
 }
 
-// GetStorageKey returns the key that is used to identify the TransactionMetadata in the objectstorage.
-func (transactionMetadata *TransactionMetadata) GetStorageKey() []byte {
+// ObjectStorageKey returns the key that is used to identify the TransactionMetadata in the objectstorage.
+func (transactionMetadata *TransactionMetadata) ObjectStorageKey() []byte {
 	return transactionMetadata.id.Bytes()
 }
 
@@ -163,15 +163,15 @@ func (transactionMetadata *TransactionMetadata) Update(other objectstorage.Stora
 	panic("update forbidden")
 }
 
-// MarshalBinary marshals the TransactionMetadata object into a sequence of bytes and matches the encoding.BinaryMarshaler
+// ObjectStorageValue marshals the TransactionMetadata object into a sequence of bytes and matches the encoding.BinaryMarshaler
 // interface.
-func (transactionMetadata *TransactionMetadata) MarshalBinary() ([]byte, error) {
-	return transactionMetadata.Bytes(), nil
+func (transactionMetadata *TransactionMetadata) ObjectStorageValue() []byte {
+	return transactionMetadata.Bytes()
 }
 
-// UnmarshalBinary restores the values of a TransactionMetadata object from a sequence of bytes and matches the
+// UnmarshalObjectStorageValue restores the values of a TransactionMetadata object from a sequence of bytes and matches the
 // encoding.BinaryUnmarshaler interface.
-func (transactionMetadata *TransactionMetadata) UnmarshalBinary(data []byte) (err error) {
+func (transactionMetadata *TransactionMetadata) UnmarshalObjectStorageValue(data []byte) (err error) {
 	_, err, _ = TransactionMetadataFromBytes(data, transactionMetadata)
 
 	return
@@ -211,3 +211,6 @@ func (cachedTransactionMetadata *CachedTransactionMetadata) Unwrap() *Transactio
 		}
 	}
 }
+
+// Interface contract: make compiler warn if the interface is not implemented correctly.
+var _ objectstorage.StorableObject = &TransactionMetadata{}
diff --git a/packages/binary/valuetransfer/tangle/transactionoutputmetadata.go b/packages/binary/valuetransfer/tangle/transactionoutputmetadata.go
index 9e0c15feea79b708abdc6db89d573444d98da3ea..75ebbb5aff9efb1b6d0904164316785d9eafa474 100644
--- a/packages/binary/valuetransfer/tangle/transactionoutputmetadata.go
+++ b/packages/binary/valuetransfer/tangle/transactionoutputmetadata.go
@@ -4,10 +4,10 @@ import (
 	"sync"
 	"time"
 
+	"github.com/iotaledger/hive.go/marshalutil"
 	"github.com/iotaledger/hive.go/objectstorage"
 	"github.com/iotaledger/hive.go/stringify"
 
-	"github.com/iotaledger/goshimmer/packages/binary/marshalutil"
 	"github.com/iotaledger/goshimmer/packages/binary/valuetransfer/transaction"
 )
 
@@ -61,7 +61,7 @@ func TransactionOutputMetadataFromBytes(bytes []byte, optionalTargetObject ...*T
 }
 
 // TransactionOutputMetadataFromStorage is the factory method for TransactionOutputMetadata objects stored in the objectstorage. The bytes and the content
-// will be filled by the objectstorage, by subsequently calling MarshalBinary.
+// will be filled by the objectstorage, by subsequently calling ObjectStorageValue.
 func TransactionOutputMetadataFromStorage(storageKey []byte) objectstorage.StorableObject {
 	result := &TransactionOutputMetadata{}
 
@@ -153,30 +153,32 @@ func (transactionOutputMetadata *TransactionOutputMetadata) String() string {
 	)
 }
 
-// GetStorageKey returns the key that is used to identify the TransactionOutputMetadata in the objectstorage.
-func (transactionOutputMetadata *TransactionOutputMetadata) GetStorageKey() []byte {
+// ObjectStorageKey returns the key that is used to identify the TransactionOutputMetadata in the objectstorage.
+func (transactionOutputMetadata *TransactionOutputMetadata) ObjectStorageKey() []byte {
 	return transactionOutputMetadata.id.Bytes()
 }
 
-// Update is disabled and panics if it ever gets called - updates are supposed to happen through the setters.
-func (transactionOutputMetadata *TransactionOutputMetadata) Update(other objectstorage.StorableObject) {
-	panic("update forbidden")
+// ObjectStorageValue returns the bytes, that are stored in the value part of the k/v store.
+func (transactionOutputMetadata *TransactionOutputMetadata) ObjectStorageValue() []byte {
+	return transactionOutputMetadata.Bytes()
 }
 
-// MarshalBinary marshals the TransactionOutputMetadata object into a sequence of bytes and matches the encoding.BinaryMarshaler
-// interface.
-func (transactionOutputMetadata *TransactionOutputMetadata) MarshalBinary() ([]byte, error) {
-	return transactionOutputMetadata.Bytes(), nil
-}
-
-// UnmarshalBinary restores the values of a TransactionOutputMetadata object from a sequence of bytes and matches the
+// UnmarshalObjectStorageValue restores the values of a TransactionOutputMetadata object from a sequence of bytes and matches the
 // encoding.BinaryUnmarshaler interface.
-func (transactionOutputMetadata *TransactionOutputMetadata) UnmarshalBinary(data []byte) (err error) {
+func (transactionOutputMetadata *TransactionOutputMetadata) UnmarshalObjectStorageValue(data []byte) (err error) {
 	_, err, _ = TransactionOutputMetadataFromBytes(data, transactionOutputMetadata)
 
 	return
 }
 
+// Update is disabled and panics if it ever gets called - updates are supposed to happen through the setters.
+func (transactionOutputMetadata *TransactionOutputMetadata) Update(other objectstorage.StorableObject) {
+	panic("update forbidden")
+}
+
+// Interface contract: make compiler warn if the interface is not implemented correctly.
+var _ objectstorage.StorableObject = &TransactionOutputMetadata{}
+
 // CachedTransactionOutputMetadata is a wrapper for the object storage, that takes care of type casting the TransactionOutputMetadata objects.
 // Since go does not have generics (yet), the object storage works based on the generic "interface{}" type, which means
 // that we have to regularly type cast the returned objects, to match the expected type. To reduce the burden of
diff --git a/packages/binary/valuetransfer/transaction/id.go b/packages/binary/valuetransfer/transaction/id.go
index 99b954bb847782596fc0593a78c146e0a3b412e7..3352d007cedf0082fe16cf08bf31acebd8396483 100644
--- a/packages/binary/valuetransfer/transaction/id.go
+++ b/packages/binary/valuetransfer/transaction/id.go
@@ -4,9 +4,8 @@ import (
 	"crypto/rand"
 	"fmt"
 
+	"github.com/iotaledger/hive.go/marshalutil"
 	"github.com/mr-tron/base58"
-
-	"github.com/iotaledger/goshimmer/packages/binary/marshalutil"
 )
 
 // Id is the data type that represents the identifier for a Transaction.
diff --git a/packages/binary/valuetransfer/transaction/inputs.go b/packages/binary/valuetransfer/transaction/inputs.go
index 49f07e965add261dd8518f7f125e0489895e17ad..255a485027831cfde98e30845de50d6f2302d7f9 100644
--- a/packages/binary/valuetransfer/transaction/inputs.go
+++ b/packages/binary/valuetransfer/transaction/inputs.go
@@ -2,8 +2,9 @@ package transaction
 
 import (
 	"github.com/iotaledger/goshimmer/packages/binary/datastructure/orderedmap"
-	"github.com/iotaledger/goshimmer/packages/binary/marshalutil"
 	"github.com/iotaledger/goshimmer/packages/binary/valuetransfer/address"
+
+	"github.com/iotaledger/hive.go/marshalutil"
 )
 
 type Inputs struct {
diff --git a/packages/binary/valuetransfer/transaction/output.go b/packages/binary/valuetransfer/transaction/output.go
index 949434dcb5c97c5749ccde643e0a0c0fb43db4a7..270e73fcf940c55fdd632c6370673f3a52df33a3 100644
--- a/packages/binary/valuetransfer/transaction/output.go
+++ b/packages/binary/valuetransfer/transaction/output.go
@@ -1,11 +1,11 @@
 package transaction
 
 import (
-	"fmt"
+	"time"
 
+	"github.com/iotaledger/hive.go/marshalutil"
 	"github.com/iotaledger/hive.go/objectstorage"
 
-	"github.com/iotaledger/goshimmer/packages/binary/marshalutil"
 	"github.com/iotaledger/goshimmer/packages/binary/valuetransfer/address"
 	"github.com/iotaledger/goshimmer/packages/binary/valuetransfer/balance"
 )
@@ -14,6 +14,8 @@ import (
 type Output struct {
 	address       address.Address
 	transactionId Id
+	solid         bool
+	solidSince    time.Time
 	balances      []*balance.Balance
 
 	objectstorage.StorableObjectFlags
@@ -25,19 +27,66 @@ func NewOutput(address address.Address, transactionId Id, balances []*balance.Ba
 	return &Output{
 		address:       address,
 		transactionId: transactionId,
+		solid:         false,
+		solidSince:    time.Time{},
 		balances:      balances,
 
 		storageKey: marshalutil.New().WriteBytes(address.Bytes()).WriteBytes(transactionId.Bytes()).Bytes(),
 	}
 }
 
-// OutputFromStorage get's called when we restore a Output from the storage.
+// OutputFromBytes unmarshals an Output object from a sequence of bytes.
+// It either creates a new object or fills the optionally provided object with the parsed information.
+func OutputFromBytes(bytes []byte, optionalTargetObject ...*Output) (result *Output, err error, consumedBytes int) {
+	// determine the target object that will hold the unmarshaled information
+	switch len(optionalTargetObject) {
+	case 0:
+		result = &Output{}
+	case 1:
+		result = optionalTargetObject[0]
+	default:
+		panic("too many arguments in call to OutputFromBytes")
+	}
+
+	// parse the bytes
+	marshalUtil := marshalutil.New(bytes)
+	if result.address, err = address.Parse(marshalUtil); err != nil {
+		return
+	}
+	if result.transactionId, err = ParseId(marshalUtil); err != nil {
+		return
+	}
+	if result.solid, err = marshalUtil.ReadBool(); err != nil {
+		return
+	}
+	if result.solidSince, err = marshalUtil.ReadTime(); err != nil {
+		return
+	}
+	var balanceCount uint32
+	if balanceCount, err = marshalUtil.ReadUint32(); err != nil {
+		return
+	} else {
+		result.balances = make([]*balance.Balance, balanceCount)
+		for i := uint32(0); i < balanceCount; i++ {
+			result.balances[i], err = balance.Parse(marshalUtil)
+			if err != nil {
+				return
+			}
+		}
+	}
+	result.storageKey = marshalutil.New().WriteBytes(result.address.Bytes()).WriteBytes(result.transactionId.Bytes()).Bytes()
+	consumedBytes = marshalUtil.ReadOffset()
+
+	return
+}
+
+// OutputFromStorageKey get's called when we restore a Output from the storage.
 // In contrast to other database models, it unmarshals some information from the key so we simply store the key before
-// it gets handed over to UnmarshalBinary (by the ObjectStorage).
-func OutputFromStorage(keyBytes []byte) objectstorage.StorableObject {
+// it gets handed over to UnmarshalObjectStorageValue (by the ObjectStorage).
+func OutputFromStorageKey(keyBytes []byte) (objectstorage.StorableObject, error) {
 	return &Output{
-		storageKey: marshalutil.New(keyBytes).Bytes(true),
-	}
+		storageKey: keyBytes[:OutputIdLength],
+	}, nil
 }
 
 // Address returns the address that this output belongs to.
@@ -55,58 +104,37 @@ func (output *Output) Balances() []*balance.Balance {
 	return output.balances
 }
 
-// MarshalBinary marshals the balances into a sequence of bytes - the address and transaction id are stored inside the key
+// ObjectStorageKey returns the key that is used to store the object in the database.
+// It is required to match StorableObject interface.
+func (output *Output) ObjectStorageKey() []byte {
+	return marshalutil.New(OutputIdLength).
+		WriteBytes(output.address.Bytes()).
+		WriteBytes(output.transactionId.Bytes()).
+		Bytes()
+}
+
+// ObjectStorageValue marshals the balances into a sequence of bytes - the address and transaction id are stored inside the key
 // and are ignored here.
-func (output *Output) MarshalBinary() (data []byte, err error) {
+func (output *Output) ObjectStorageValue() (data []byte) {
 	// determine amount of balances in the output
 	balanceCount := len(output.balances)
 
 	// initialize helper
 	marshalUtil := marshalutil.New(4 + balanceCount*balance.Length)
-
-	// marshal the amount of balances
+	marshalUtil.WriteBool(output.solid)
+	marshalUtil.WriteTime(output.solidSince)
 	marshalUtil.WriteUint32(uint32(balanceCount))
-
-	// marshal balances
-	for _, balance := range output.balances {
-		marshalUtil.WriteBytes(balance.Bytes())
+	for _, balanceToMarshal := range output.balances {
+		marshalUtil.WriteBytes(balanceToMarshal.Bytes())
 	}
 
 	return
 }
 
-// UnmarshalBinary restores a Output from a serialized version in the ObjectStorage with parts of the object
+// UnmarshalObjectStorageValue restores a Output from a serialized version in the ObjectStorage with parts of the object
 // being stored in its key rather than the content of the database to reduce storage requirements.
-func (output *Output) UnmarshalBinary(data []byte) (err error) {
-	// check if the storageKey has been set
-	if output.storageKey == nil {
-		return fmt.Errorf("missing storageKey when trying to unmarshal Output (it contains part of the information)")
-	}
-
-	// parse information from storageKey
-	storageKeyUnmarshaler := marshalutil.New(output.storageKey)
-	output.address, err = address.Parse(storageKeyUnmarshaler)
-	if err != nil {
-		return
-	}
-	output.transactionId, err = ParseId(storageKeyUnmarshaler)
-	if err != nil {
-		return
-	}
-
-	// parse information from content bytes
-	contentUnmarshaler := marshalutil.New(data)
-	balanceCount, err := contentUnmarshaler.ReadUint32()
-	if err != nil {
-		return
-	}
-	output.balances = make([]*balance.Balance, balanceCount)
-	for i := uint32(0); i < balanceCount; i++ {
-		output.balances[i], err = balance.Parse(contentUnmarshaler)
-		if err != nil {
-			return
-		}
-	}
+func (output *Output) UnmarshalObjectStorageValue(data []byte) (err error) {
+	_, err, _ = OutputFromBytes(marshalutil.New(output.storageKey).WriteBytes(data).Bytes(), output)
 
 	return
 }
@@ -116,11 +144,5 @@ func (output *Output) Update(other objectstorage.StorableObject) {
 	panic("this object should never be updated")
 }
 
-// GetStorageKey returns the key that is used to store the object in the database.
-// It is required to match StorableObject interface.
-func (output *Output) GetStorageKey() []byte {
-	return output.storageKey
-}
-
 // define contract (ensure that the struct fulfills the given interface)
 var _ objectstorage.StorableObject = &Output{}
diff --git a/packages/binary/valuetransfer/transaction/outputid.go b/packages/binary/valuetransfer/transaction/outputid.go
index 891cd5c09b678dfd7f097e179a25ce3fb6460c3f..6f0640c2f314f424f4711167a6869cbf60dcade9 100644
--- a/packages/binary/valuetransfer/transaction/outputid.go
+++ b/packages/binary/valuetransfer/transaction/outputid.go
@@ -3,7 +3,8 @@ package transaction
 import (
 	"github.com/mr-tron/base58"
 
-	"github.com/iotaledger/goshimmer/packages/binary/marshalutil"
+	"github.com/iotaledger/hive.go/marshalutil"
+
 	"github.com/iotaledger/goshimmer/packages/binary/valuetransfer/address"
 )
 
diff --git a/packages/binary/valuetransfer/transaction/outputs.go b/packages/binary/valuetransfer/transaction/outputs.go
index 3166ac938e9e355218f9a8632c926229dac6a50f..daf995bbea3799e65868699dad447f0f79ec9fd0 100644
--- a/packages/binary/valuetransfer/transaction/outputs.go
+++ b/packages/binary/valuetransfer/transaction/outputs.go
@@ -2,8 +2,9 @@ package transaction
 
 import (
 	"github.com/iotaledger/goshimmer/packages/binary/datastructure/orderedmap"
-	"github.com/iotaledger/goshimmer/packages/binary/marshalutil"
 	"github.com/iotaledger/goshimmer/packages/binary/valuetransfer/address"
+	"github.com/iotaledger/hive.go/marshalutil"
+
 	"github.com/iotaledger/goshimmer/packages/binary/valuetransfer/balance"
 )
 
diff --git a/packages/binary/valuetransfer/transaction/signatures.go b/packages/binary/valuetransfer/transaction/signatures.go
index 843389e3cb50b025fe7895de56a1258e004bcb52..fd9a14240d1716fcf28254a2ad5337afde1379bf 100644
--- a/packages/binary/valuetransfer/transaction/signatures.go
+++ b/packages/binary/valuetransfer/transaction/signatures.go
@@ -1,8 +1,9 @@
 package transaction
 
 import (
+	"github.com/iotaledger/hive.go/marshalutil"
+
 	"github.com/iotaledger/goshimmer/packages/binary/datastructure/orderedmap"
-	"github.com/iotaledger/goshimmer/packages/binary/marshalutil"
 	"github.com/iotaledger/goshimmer/packages/binary/valuetransfer/address"
 	"github.com/iotaledger/goshimmer/packages/binary/valuetransfer/address/signaturescheme"
 )
diff --git a/packages/binary/valuetransfer/transaction/transaction.go b/packages/binary/valuetransfer/transaction/transaction.go
index 705a62ab8278e0bda05a23b95914aa91188853f3..20e1c2a440c9d849691317c810f4dc2414a59762 100644
--- a/packages/binary/valuetransfer/transaction/transaction.go
+++ b/packages/binary/valuetransfer/transaction/transaction.go
@@ -4,12 +4,12 @@ import (
 	"fmt"
 	"sync"
 
+	"github.com/iotaledger/hive.go/marshalutil"
 	"github.com/iotaledger/hive.go/objectstorage"
 	"github.com/iotaledger/hive.go/stringify"
 	"github.com/mr-tron/base58"
 	"golang.org/x/crypto/blake2b"
 
-	"github.com/iotaledger/goshimmer/packages/binary/marshalutil"
 	"github.com/iotaledger/goshimmer/packages/binary/valuetransfer/address"
 	"github.com/iotaledger/goshimmer/packages/binary/valuetransfer/address/signaturescheme"
 )
@@ -280,7 +280,7 @@ func (transaction *Transaction) String() string {
 // define contract (ensure that the struct fulfills the given interface)
 var _ objectstorage.StorableObject = &Transaction{}
 
-func (transaction *Transaction) GetStorageKey() []byte {
+func (transaction *Transaction) ObjectStorageKey() []byte {
 	id := transaction.Id()
 
 	return id[:]
@@ -290,12 +290,12 @@ func (transaction *Transaction) Update(other objectstorage.StorableObject) {
 	panic("update forbidden")
 }
 
-// MarshalBinary returns a bytes representation of the Transaction by implementing the encoding.BinaryMarshaler interface.
-func (transaction *Transaction) MarshalBinary() ([]byte, error) {
-	return transaction.Bytes(), nil
+// ObjectStorageValue returns a bytes representation of the Transaction by implementing the encoding.BinaryMarshaler interface.
+func (transaction *Transaction) ObjectStorageValue() []byte {
+	return transaction.Bytes()
 }
 
-func (transaction *Transaction) UnmarshalBinary(bytes []byte) (err error) {
+func (transaction *Transaction) UnmarshalObjectStorageValue(bytes []byte) (err error) {
 	_, err, _ = FromBytes(bytes, transaction)
 
 	return