diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 5d5bbe80f56f1e601b59d1c2d15b1ee269e36c0a..4a344591818545dcf0ebccf75d15fe54874d8ee4 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -90,7 +90,7 @@ bindings-ios:
     - go get golang.org/x/mobile/bind
     - go install golang.org/x/mobile/cmd/gomobile@latest
     - gomobile init
-    - gomobile bind -target ios gitlab.com/elixxir/client/bindings
+    - gomobile bind -target ios,iossimulator,macos gitlab.com/elixxir/client/bindings
     - ls
     - zip -r iOS.zip Bindings.xcframework
   artifacts:
diff --git a/auth/callbacks.go b/auth/callbacks.go
index 273ff6b0b7af5b36ff53d44e265ebaeaab0183cd..787f15a0068c3e7a2547e8438785b45a8b461689 100644
--- a/auth/callbacks.go
+++ b/auth/callbacks.go
@@ -1,7 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2022 Privategrity Corporation                                   /
-//                                                                             /
-// All rights reserved.                                                        /
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package auth
diff --git a/auth/confirm.go b/auth/confirm.go
index 05c1bc136ac567749d1115b7e13d1c7091da1a6b..0b7278c6e1f08b8535384d729b95c46eba650b04 100644
--- a/auth/confirm.go
+++ b/auth/confirm.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package auth
 
@@ -132,7 +132,7 @@ func (s *state) confirm(partner contact.Contact, serviceTag string) (
 
 			/*send message*/
 			if err = s.store.StoreConfirmation(partner.ID, baseFmt.Marshal(),
-				mac, fp); err == nil {
+				mac, fp); err != nil {
 				jww.WARN.Printf("Failed to store confirmation for replay "+
 					"for relationship between %s and %s, cannot be replayed: %+v",
 					partner.ID, s.e2e.GetReceptionID(), err)
@@ -171,8 +171,8 @@ func sendAuthConfirm(net cmixClient, partner *id.ID,
 	}
 
 	em := fmt.Sprintf("Confirm Request with %s (msgDigest: %s) sent on round %d",
-		partner, format.DigestContents(payload), sentRound)
+		partner, format.DigestContents(payload), sentRound.ID)
 	jww.INFO.Print(em)
 	event.Report(1, "Auth", "SendConfirm", em)
-	return sentRound, nil
+	return sentRound.ID, nil
 }
diff --git a/auth/fmt.go b/auth/fmt.go
index 6ec925c7efd8be0cbd1b48ff09b1766e0080bd03..6318b7474a0fe91c22fedbfd9ef2cc91c8a8d729 100644
--- a/auth/fmt.go
+++ b/auth/fmt.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package auth
 
diff --git a/auth/fmt_test.go b/auth/fmt_test.go
index 59e63cba01f78904fa594947a40726b26492ff5d..0c045402062f0d4f7d3bda1ab2723aa5a9be6abd 100644
--- a/auth/fmt_test.go
+++ b/auth/fmt_test.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package auth
 
diff --git a/auth/interface.go b/auth/interface.go
index b45ba36e9c7d4a135a0f7adf48416b1e1cbf1112..c515973886b9387d3442ee6f134aa47a428bb0ea 100644
--- a/auth/interface.go
+++ b/auth/interface.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package auth
 
 import (
@@ -134,7 +141,7 @@ type cmixClient interface {
 	DeleteFingerprint(identity *id.ID, fingerprint format.Fingerprint)
 	Send(recipient *id.ID, fingerprint format.Fingerprint,
 		service message.Service, payload, mac []byte, cmixParams cmix.CMIXParams) (
-		id.Round, ephemeral.Id, error)
+		rounds.Round, ephemeral.Id, error)
 }
 
 // e2eHandler is a sub-interface of e2e.Handler containing
diff --git a/auth/params.go b/auth/params.go
index 907fa4ad825c3c6ef068d9dc7e6cd8b92d70a773..01fa5ba810e108dc72407fd0e0bf90bccbf54904 100644
--- a/auth/params.go
+++ b/auth/params.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package auth
 
 import (
diff --git a/auth/receivedConfirm.go b/auth/receivedConfirm.go
index ad30186d15c911dbc739495ccf58df4bdcf05818..0b1109cd9410fe19b75cc891cb7eac9604ed4da9 100644
--- a/auth/receivedConfirm.go
+++ b/auth/receivedConfirm.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package auth
 
 import (
diff --git a/auth/receivedRequest.go b/auth/receivedRequest.go
index 4e3325996a6ca5c558d3531a019c68c92f026bf3..e94b82598ad12a5bb2b24246074f9936040b6d04 100644
--- a/auth/receivedRequest.go
+++ b/auth/receivedRequest.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package auth
 
 import (
diff --git a/auth/replayConfirm.go b/auth/replayConfirm.go
index 09540fe298680ffbc1a2bfba522306b22bd8f781..4581479061d173f0327d42bdd5129c4fa67147bc 100644
--- a/auth/replayConfirm.go
+++ b/auth/replayConfirm.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package auth
 
 import "gitlab.com/xx_network/primitives/id"
diff --git a/auth/request.go b/auth/request.go
index d37385815b55d2f6b1e87fabc5e1f167bb704360..17db1b2f64572d73a7601e606d72fa1d2fb5c2b1 100644
--- a/auth/request.go
+++ b/auth/request.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package auth
 
@@ -82,6 +82,11 @@ func (s *state) request(partner contact.Contact, myfacts fact.FactList,
 	historicalDHPub := diffieHellman.GeneratePublicKey(historicalDHPriv,
 		dhGrp)
 
+	if !dhGrp.Inside(partner.DhPubKey.GetLargeInt()) {
+		return 0, errors.Errorf("partner's DH public key is not in the E2E "+
+			"group; E2E group fingerprint is %d and DH key has %d",
+			dhGrp.GetFingerprint(), partner.DhPubKey.GetGroupFingerprint())
+	}
 	ownership := cAuth.MakeOwnershipProof(historicalDHPriv,
 		partner.DhPubKey, dhGrp)
 	confirmFp := cAuth.MakeOwnershipProofFP(ownership)
@@ -159,10 +164,10 @@ func (s *state) request(partner contact.Contact, myfacts fact.FactList,
 	}
 
 	em := fmt.Sprintf("Auth Request with %s (msgDigest: %s) sent"+
-		" on round %d", partner.ID, format.DigestContents(contents), round)
+		" on round %d", partner.ID, format.DigestContents(contents), round.ID)
 	jww.INFO.Print(em)
 	s.event.Report(1, "Auth", "RequestSent", em)
-	return round, nil
+	return round.ID, nil
 
 }
 
diff --git a/auth/reset.go b/auth/reset.go
index 9f6114f466534efc6e27d2382d6caa71abb726f3..5521a6089ced2c8bb59ab4d599119cfdabaa06d7 100644
--- a/auth/reset.go
+++ b/auth/reset.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package auth
 
 import (
diff --git a/auth/sentRequestHandler.go b/auth/sentRequestHandler.go
index 5d336b90a31fb0b4d2f1fc62429442ec6065d37f..f0e40fffb5f2fe47f68252dbbb9dc3cac3349642 100644
--- a/auth/sentRequestHandler.go
+++ b/auth/sentRequestHandler.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package auth
 
 import (
diff --git a/auth/state.go b/auth/state.go
index e226a01e7bdf0cf2575e6f3d0ed13983ef38c0f7..a18baa7656ba4db4b812372f561732b3de172788 100644
--- a/auth/state.go
+++ b/auth/state.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package auth
 
diff --git a/auth/state_test.go b/auth/state_test.go
index 34b670453b4a5052d71868ebeccd4d8030f1a511..5dc12aca17520550e4857647e40c32bed212fcc4 100644
--- a/auth/state_test.go
+++ b/auth/state_test.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package auth
 
@@ -69,8 +69,8 @@ func (mnm *mockNetManager) AddFingerprint(identity *id.ID, fingerprint format.Fi
 func (mnm *mockNetManager) DeleteFingerprint(identity *id.ID, fingerprint format.Fingerprint) {}
 func (mnm *mockNetManager) Send(recipient *id.ID, fingerprint format.Fingerprint,
 	service message.Service, payload, mac []byte, cmixParams cmix.CMIXParams) (
-	id.Round, ephemeral.Id, error) {
-	return id.Round(5), ephemeral.Id{}, nil
+	rounds.Round, ephemeral.Id, error) {
+	return rounds.Round{ID: 5}, ephemeral.Id{}, nil
 }
 
 type mockE2E struct {
diff --git a/auth/store/confirmation.go b/auth/store/confirmation.go
index c972fd8af974060824eaa735a9f6a371a56b12a8..a7619fb3bfea265e1790cd0c1dc3cb6d4c5964a9 100644
--- a/auth/store/confirmation.go
+++ b/auth/store/confirmation.go
@@ -1,8 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package store
@@ -48,8 +48,7 @@ func (s *Store) StoreConfirmation(partner *id.ID,
 		Data:      confirmBytes,
 	}
 
-	return s.kv.Set(makeConfirmationKey(partner),
-		currentConfirmationVersion, obj)
+	return s.kv.Set(makeConfirmationKey(partner), obj)
 }
 
 // LoadConfirmation loads the confirmation for the given partner and fingerprint
diff --git a/auth/store/confirmation_test.go b/auth/store/confirmation_test.go
index 2bc188cd4429cf1ff27f5166dbbfc1c4457a13d5..570aeb0aa4077129ca429a7b8d27f0ae36c2ba32 100644
--- a/auth/store/confirmation_test.go
+++ b/auth/store/confirmation_test.go
@@ -1,8 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package store
diff --git a/auth/store/deletion.go b/auth/store/deletion.go
index d5fb746a72fa9f02466a9ebe7a73da3b86499616..0da70d1d114530f78c9072d5bf7774ada489c056 100644
--- a/auth/store/deletion.go
+++ b/auth/store/deletion.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package store
 
 import (
diff --git a/auth/store/fingerprint.go b/auth/store/fingerprint.go
index 3a99453a985f02f86e0e54636cd55b1249dfebbc..4f0d71429c53d33c19efdf4037e7ad1e4a4594b5 100644
--- a/auth/store/fingerprint.go
+++ b/auth/store/fingerprint.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package store
 
diff --git a/auth/store/previousNegotiations.go b/auth/store/previousNegotiations.go
index be8d701f082ef99de72cd67f9a1d4c0b01b6bd9f..6bc8931d78827ade1af9df355288ee761ca497d7 100644
--- a/auth/store/previousNegotiations.go
+++ b/auth/store/previousNegotiations.go
@@ -1,8 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package store
@@ -16,7 +16,6 @@ import (
 	jww "github.com/spf13/jwalterweatherman"
 	"gitlab.com/elixxir/client/storage/versioned"
 	"gitlab.com/elixxir/crypto/e2e/auth"
-	"gitlab.com/elixxir/ekv"
 	"gitlab.com/xx_network/primitives/id"
 	"gitlab.com/xx_network/primitives/netTime"
 )
@@ -112,7 +111,7 @@ func (s *Store) savePreviousNegotiations() error {
 		Data:      marshalPreviousNegotiations(s.previousNegotiations),
 	}
 
-	return s.kv.Set(negotiationPartnersKey, negotiationPartnersVersion, obj)
+	return s.kv.Set(negotiationPartnersKey, obj)
 }
 
 // newOrLoadPreviousNegotiations loads the list of previousNegotiations partners
@@ -122,7 +121,7 @@ func (s *Store) newOrLoadPreviousNegotiations() (map[id.ID]bool, error) {
 	obj, err := s.kv.Get(negotiationPartnersKey, negotiationPartnersVersion)
 
 	// V0 Upgrade Path
-	if !ekv.Exists(err) {
+	if !s.kv.Exists(err) {
 		upgradeErr := upgradePreviousNegotiationsV0(s.kv)
 		if upgradeErr != nil {
 			return nil, errors.Wrapf(err, "%+v", upgradeErr)
@@ -132,7 +131,7 @@ func (s *Store) newOrLoadPreviousNegotiations() (map[id.ID]bool, error) {
 	}
 
 	// Note: if it still doesn't exist, return an empty one.
-	if err != nil && !ekv.Exists(err) {
+	if err != nil && !s.kv.Exists(err) {
 		newPreviousNegotiations := make(map[id.ID]bool)
 		return newPreviousNegotiations, nil
 	} else if err != nil {
@@ -188,8 +187,7 @@ func saveNegotiationFingerprints(
 		Data:      marshalNegotiationFingerprints(fingerprints...),
 	}
 
-	return kv.Set(makeNegotiationFingerprintsKey(partner),
-		currentNegotiationFingerprintsVersion, obj)
+	return kv.Set(makeNegotiationFingerprintsKey(partner), obj)
 }
 
 // loadNegotiationFingerprints loads the list of sentByFingerprints for the given
@@ -272,7 +270,7 @@ func unmarshalPreviousNegotiationsV0(buf []byte) map[id.ID]struct{} {
 // to V1
 func upgradePreviousNegotiationsV0(kv *versioned.KV) error {
 	obj, err := kv.Get(negotiationPartnersKey, 0)
-	if !ekv.Exists(err) {
+	if !kv.Exists(err) {
 		return nil
 	}
 
@@ -287,5 +285,5 @@ func upgradePreviousNegotiationsV0(kv *versioned.KV) error {
 		Data: marshalPreviousNegotiations(
 			newPrevNegotiations),
 	}
-	return kv.Set(negotiationPartnersKey, negotiationPartnersVersion, obj)
+	return kv.Set(negotiationPartnersKey, obj)
 }
diff --git a/auth/store/previousNegotiations_test.go b/auth/store/previousNegotiations_test.go
index 2d8234a45adf372b5883eb7bade2714f6574619a..e99414f7f5a8fb271e90941a78796da84df3fbe5 100644
--- a/auth/store/previousNegotiations_test.go
+++ b/auth/store/previousNegotiations_test.go
@@ -1,8 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package store
diff --git a/auth/store/receivedRequest.go b/auth/store/receivedRequest.go
index 4bb0c5216a6abd2b48d7fdc779c493d5a69b6597..63b338269f666f816b7d40e65db21417e7331b83 100644
--- a/auth/store/receivedRequest.go
+++ b/auth/store/receivedRequest.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package store
 
 import (
@@ -10,7 +17,6 @@ import (
 	util "gitlab.com/elixxir/client/storage/utility"
 	"gitlab.com/elixxir/client/storage/versioned"
 	"gitlab.com/elixxir/crypto/contact"
-	"gitlab.com/elixxir/ekv"
 	"gitlab.com/xx_network/primitives/id"
 )
 
@@ -27,7 +33,7 @@ type ReceivedRequest struct {
 	round rounds.Round
 
 	//lock to make sure only one operator at a time
-	mux *sync.Mutex
+	mux sync.Mutex
 }
 
 func newReceivedRequest(kv *versioned.KV, c contact.Contact,
@@ -54,7 +60,6 @@ func newReceivedRequest(kv *versioned.KV, c contact.Contact,
 		partner:          c,
 		theirSidHPubKeyA: key,
 		round:            round,
-		mux:              &sync.Mutex{},
 	}
 }
 
@@ -77,11 +82,11 @@ func loadReceivedRequest(kv *versioned.KV, partner *id.ID) (
 	}
 
 	round, err := rounds.LoadRound(kv, makeRoundKey(partner))
-	if err != nil && ekv.Exists(err) {
+	if err != nil && kv.Exists(err) {
 		return nil, errors.WithMessagef(err, "Failed to Load "+
 			"round request was received on with %s",
 			partner)
-	} else if err != nil && !ekv.Exists(err) {
+	} else if err != nil && !kv.Exists(err) {
 		jww.WARN.Printf("No round info for partner %s", partner)
 	}
 
diff --git a/auth/store/request.go b/auth/store/request.go
index 0678d9c5c220c29f88c49aa286dfd592454a95be..88c721fdd09b23c20e6bfd3b1922ec5518fd0b98 100644
--- a/auth/store/request.go
+++ b/auth/store/request.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package store
 
diff --git a/auth/store/sentRequest.go b/auth/store/sentRequest.go
index 5f5b8a69e1e193ada63726e1f24c31e03a37973c..7b0283766b9b0359157261bb327a263f0e627ab2 100644
--- a/auth/store/sentRequest.go
+++ b/auth/store/sentRequest.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package store
 
@@ -19,7 +19,6 @@ import (
 	sidhinterface "gitlab.com/elixxir/client/interfaces/sidh"
 	"gitlab.com/elixxir/client/storage/versioned"
 	"gitlab.com/elixxir/crypto/cyclic"
-	"gitlab.com/elixxir/ekv"
 	"gitlab.com/elixxir/primitives/format"
 	"gitlab.com/xx_network/primitives/id"
 	"gitlab.com/xx_network/primitives/netTime"
@@ -77,7 +76,7 @@ func loadSentRequest(kv *versioned.KV, partner *id.ID, grp *cyclic.Group) (*Sent
 	obj, err := kv.Get(srKey, currentSentRequestVersion)
 
 	// V0 Upgrade Path
-	if !ekv.Exists(err) {
+	if !kv.Exists(err) {
 		upgradeErr := upgradeSentRequestKeyV0(kv, partner)
 		if upgradeErr != nil {
 			return nil, errors.Wrapf(err, "%+v", upgradeErr)
@@ -211,8 +210,7 @@ func (sr *SentRequest) save() error {
 		Data:      data,
 	}
 
-	return sr.kv.Set(makeSentRequestKey(sr.partner),
-		currentSentRequestVersion, &obj)
+	return sr.kv.Set(makeSentRequestKey(sr.partner), &obj)
 }
 
 func (sr *SentRequest) delete() {
@@ -296,7 +294,7 @@ func upgradeSentRequestKeyV0(kv *versioned.KV, partner *id.ID) error {
 
 	// Note: uses same encoding, just different keys
 	obj.Version = 1
-	err = kv.Set(makeSentRequestKey(partner), 1, obj)
+	err = kv.Set(makeSentRequestKey(partner), obj)
 	if err != nil {
 		return err
 	}
diff --git a/auth/store/sentRequestHandler.go b/auth/store/sentRequestHandler.go
index 4a8afac3ea867ea5eb2570f978ba6ff88be0f663..e0466210679b3f83d9256f528b9b309702c3629d 100644
--- a/auth/store/sentRequestHandler.go
+++ b/auth/store/sentRequestHandler.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package store
 
 // SentRequestHandler allows the lower level to assign and remove services
diff --git a/auth/store/store.go b/auth/store/store.go
index e5496b2d7c88751b36250f814f397ba9ae97bcef..5a42a0aa9cf2d356c62a4d23189746c16ef90349 100644
--- a/auth/store/store.go
+++ b/auth/store/store.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package store
 
@@ -23,8 +23,6 @@ import (
 	"gitlab.com/xx_network/primitives/netTime"
 )
 
-const NoRequest = "Request Not Found"
-
 const storePrefix = "requestMap"
 const requestMapKey = "map"
 
@@ -149,7 +147,7 @@ func (s *Store) save() error {
 		Data:      data,
 	}
 
-	return s.kv.Set(requestMapKey, requestMapVersion, &obj)
+	return s.kv.Set(requestMapKey, &obj)
 }
 
 // NewStore creates a new store. All passed in private keys are added as
@@ -268,16 +266,15 @@ func (s *Store) HandleReceivedRequest(partner *id.ID, handler func(*ReceivedRequ
 
 	//run the handler
 	handleErr := handler(rr)
-
 	if handleErr != nil {
 		return errors.WithMessage(handleErr, "Received error from handler")
 	}
 
 	delete(s.receivedByID, *partner)
-	s.save()
+	err := s.save()
 	rr.delete()
 
-	return nil
+	return err
 }
 
 // HandleSentRequest handles the request singly, only a single operator
@@ -311,16 +308,15 @@ func (s *Store) HandleSentRequest(partner *id.ID, handler func(request *SentRequ
 
 	//run the handler
 	handleErr := handler(sr)
-
 	if handleErr != nil {
 		return errors.WithMessage(handleErr, "Received error from handler")
 	}
 
 	delete(s.sentByID, *partner)
-	s.save()
+	err := s.save()
 	sr.delete()
 
-	return nil
+	return err
 }
 
 // GetReceivedRequest returns the contact representing the partner request
diff --git a/auth/store/store_test.go b/auth/store/store_test.go
index 4c88064c04acebb62281c108d69eeb66caac5182..acd6156c50ddca150e755826e8481fbb91c3d5f2 100644
--- a/auth/store/store_test.go
+++ b/auth/store/store_test.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package store
 
@@ -277,7 +277,7 @@ func TestStore_GetReceivedRequest_RequestDeleted(t *testing.T) {
 	}
 
 	// Check if the request's mutex is locked
-	if reflect.ValueOf(rr.mux).Elem().FieldByName("state").Int() != 0 {
+	if reflect.ValueOf(&rr.mux).Elem().FieldByName("state").Int() != 0 {
 		t.Errorf("GetReceivedRequest() did not unlock mutex.")
 	}
 }
diff --git a/auth/utils_test.go b/auth/utils_test.go
index 5f27a218e0651736ace0ca165ef44e0ef581b05d..aa4689e7ae5bc74d38470e8179fd79b1a43fac68 100644
--- a/auth/utils_test.go
+++ b/auth/utils_test.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package auth
 
 import (
@@ -61,9 +68,8 @@ func (m mockE2eHandler) StartProcesses() (stoppable.Stoppable, error) {
 }
 
 func (m mockE2eHandler) SendE2E(mt catalog.MessageType, recipient *id.ID,
-	payload []byte, params e2e.Params) ([]id.Round, cryptoE2e.MessageID,
-	time.Time, error) {
-	return nil, cryptoE2e.MessageID{}, time.Time{}, nil
+	payload []byte, params e2e.Params) (cryptoE2e.SendReport, error) {
+	return cryptoE2e.SendReport{}, nil
 }
 
 func (m mockE2eHandler) RegisterListener(senderID *id.ID,
diff --git a/auth/verify.go b/auth/verify.go
index f86aad68db374043efbb41ffb9c19048d172598c..d9a3259ecbf68067e07df6bac5dd3892a0113fb0 100644
--- a/auth/verify.go
+++ b/auth/verify.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package auth
 
diff --git a/auth/verify_test.go b/auth/verify_test.go
index 9f2a34642e241b870fa55d337c3bcf24efe519b5..81515c9732579ba7578082ee6e8b1325bc199d7f 100644
--- a/auth/verify_test.go
+++ b/auth/verify_test.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package auth
 
diff --git a/backup/backup.go b/backup/backup.go
index c6debb0888faf7f4499a060d16f2f1fae09a2082..d4cc92a408a48cd809b30a93f25bb9ea93b02e59 100644
--- a/backup/backup.go
+++ b/backup/backup.go
@@ -1,8 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package backup
diff --git a/backup/backupRestore.go b/backup/backupRestore.go
index c0a4e3ecc37c5b2ba99816d0b05c297b70884e19..6be4fd04620c011b8d3c318471e4aef04d86b700 100644
--- a/backup/backupRestore.go
+++ b/backup/backupRestore.go
@@ -1,7 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2022 Privategrity Corporation                                   /
-//                                                                             /
-// All rights reserved.                                                        /
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package backup
diff --git a/backup/backup_test.go b/backup/backup_test.go
index bcaf8cf35bb4c7d0044cbf7e2a79e445e0d9c207..900ed84ec9abfe99389f19b1d26a369048f6daae 100644
--- a/backup/backup_test.go
+++ b/backup/backup_test.go
@@ -1,8 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package backup
@@ -11,7 +11,6 @@ import (
 	"bytes"
 	"gitlab.com/elixxir/client/xxdk"
 	"reflect"
-	"strings"
 	"testing"
 	"time"
 
@@ -151,7 +150,7 @@ func Test_resumeBackup_NoKeyError(t *testing.T) {
 	rngGen := fastRNG.NewStreamGenerator(1000, 10, csprng.NewSystemRNG)
 	_, err := ResumeBackup(nil, &xxdk.Container{}, newMockE2e(t), newMockSession(t),
 		newMockUserDiscovery(), s.GetKV(), rngGen)
-	if err == nil || !strings.Contains(err.Error(), expectedErr) {
+	if err == nil || s.GetKV().Exists(err) {
 		t.Errorf("ResumeBackup did not return the expected error when no "+
 			"password is present.\nexpected: %s\nreceived: %+v", expectedErr, err)
 	}
diff --git a/backup/jsonStorage.go b/backup/jsonStorage.go
index 8ce778b56aff9c76847caf1953451d7cb6b39d5d..3e7b889f6bc2fc43ddbf14a95e01c325f39425f5 100644
--- a/backup/jsonStorage.go
+++ b/backup/jsonStorage.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package backup
 
 import (
@@ -17,7 +24,7 @@ func storeJson(json string, kv *versioned.KV) error {
 		Data:      []byte(json),
 	}
 
-	return kv.Set(jsonStorageKey, jsonStorageVersion, obj)
+	return kv.Set(jsonStorageKey, obj)
 }
 
 func loadJson(kv *versioned.KV) string {
diff --git a/backup/jsonStorage_test.go b/backup/jsonStorage_test.go
index 352f6d2d6e595fe8a6fe49da48deda570cee647c..a5eb3d2bb06ef942612fcc6b2c86992e2c9adad0 100644
--- a/backup/jsonStorage_test.go
+++ b/backup/jsonStorage_test.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package backup
 
 import (
diff --git a/backup/keyStorage.go b/backup/keyStorage.go
index 27437998775dc4a63cf4e3c996dd82f3aa68e56c..f3164957954fe1eddb24fe5eaf69133484d1b550 100644
--- a/backup/keyStorage.go
+++ b/backup/keyStorage.go
@@ -1,8 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package backup
@@ -38,7 +38,7 @@ func saveBackup(key, salt []byte, params backup.Params, kv *versioned.KV) error
 		Data:      marshalBackup(key, salt, params),
 	}
 
-	return kv.Set(cryptoStorageKey, cryptoStorageVersion, obj)
+	return kv.Set(cryptoStorageKey, obj)
 }
 
 // loadBackup loads the key, salt, and params from storage.
diff --git a/backup/utils_test.go b/backup/utils_test.go
index 9a1d03976d8df5e71cfb7d87d1e5e32ce775caf8..beecea4a4c9c94fcd21acc78ced939ef919ab143 100644
--- a/backup/utils_test.go
+++ b/backup/utils_test.go
@@ -1,8 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package backup
diff --git a/bindings/authenticatedConnection.go b/bindings/authenticatedConnection.go
index 33aac039b7bea7ff91e5f021103e22442bc615ba..70ef4cf4921658b45223a9b7f254c1c1c029b67b 100644
--- a/bindings/authenticatedConnection.go
+++ b/bindings/authenticatedConnection.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package bindings
 
@@ -34,7 +34,6 @@ func (_ *AuthenticatedConnection) IsAuthenticated() bool {
 // ConnectWithAuthentication is called by the client (i.e., the one establishing
 // connection with the server). Once a connect.Connection has been established
 // with the server, it then authenticates their identity to the server.
-// accepts a marshalled ReceptionIdentity and contact.Contact object
 func (c *Cmix) ConnectWithAuthentication(e2eId int, recipientContact,
 	e2eParamsJSON []byte) (*AuthenticatedConnection, error) {
 	if len(e2eParamsJSON) == 0 {
diff --git a/bindings/backup.go b/bindings/backup.go
index 2c5c24560184fe5d1f121e05b8df5de98ce1fc23..50aaf5c29fb0aed49682fb582e158fb698ee9b9d 100644
--- a/bindings/backup.go
+++ b/bindings/backup.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package bindings
 
@@ -55,7 +55,7 @@ type UpdateBackupFunc interface {
 // backup. Users of this function should delete the storage directory on error.
 // Users of this function should call LoadCmix as normal once this call succeeds.
 //
-// Params
+// Parameters:
 //  - ndfJSON - JSON of the NDF.
 //  - storageDir - directory for the storage files.
 //  - sessionPassword - password to decrypt the data in the storageDir.
@@ -92,10 +92,11 @@ func NewCmixFromBackup(ndfJSON, storageDir, backupPassphrase string,
 
 // InitializeBackup creates a bindings-layer Backup object.
 //
-// Params
+// Parameters:
 //  - e2eID - ID of the E2e object in the e2e tracker.
 //  - udID - ID of the UserDiscovery object in the ud tracker.
-//  - backupPassPhrase - backup passphrase provided by the user. Used to decrypt backup.
+//  - backupPassPhrase - backup passphrase provided by the user. Used to decrypt
+//    backup.
 //  - cb - the callback to be called when a backup is triggered.
 func InitializeBackup(e2eID, udID int, backupPassPhrase string,
 	cb UpdateBackupFunc) (*Backup, error) {
@@ -129,7 +130,7 @@ func InitializeBackup(e2eID, udID int, backupPassPhrase string,
 // To start the backup for the first time or to use a new password, use
 // InitializeBackup.
 //
-// Params
+// Parameters:
 //  - e2eID - ID of the E2e object in the e2e tracker.
 //  - udID - ID of the UserDiscovery object in the ud tracker.
 //  - cb - the callback to be called when a backup is triggered.
diff --git a/bindings/broadcast.go b/bindings/broadcast.go
deleted file mode 100644
index 62cce68bc271509b19f92aa4c44dac6f2c9ff7d9..0000000000000000000000000000000000000000
--- a/bindings/broadcast.go
+++ /dev/null
@@ -1,199 +0,0 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2022 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
-
-package bindings
-
-import (
-	"encoding/json"
-	"github.com/pkg/errors"
-	"gitlab.com/elixxir/client/broadcast"
-	"gitlab.com/elixxir/client/cmix"
-	"gitlab.com/elixxir/client/cmix/identity/receptionID"
-	"gitlab.com/elixxir/client/cmix/rounds"
-	cryptoBroadcast "gitlab.com/elixxir/crypto/broadcast"
-	"gitlab.com/xx_network/crypto/signature/rsa"
-	"gitlab.com/xx_network/primitives/id/ephemeral"
-)
-
-// Channel is a bindings-level struct encapsulating the broadcast.Channel client object.
-type Channel struct {
-	ch broadcast.Channel
-}
-
-// ChannelDef is the bindings representation of an elixxir/crypto broadcast.Channel object.
-//
-// Example JSON:
-//  {"Name": "My broadcast channel",
-//   "Description":"A broadcast channel for me to test things",
-//   "Salt":"gpUqW7N22sffMXsvPLE7BA==",
-//   "PubKey":"LS0tLS1CRUdJTiBSU0EgUFVCTElDIEtFWS0tLS0tCk1DZ0NJUUN2YkZVckJKRFpqT3Y0Y0MvUHZZdXNvQkFtUTFkb3Znb044aHRuUjA2T3F3SURBUUFCCi0tLS0tRU5EIFJTQSBQVUJMSUMgS0VZLS0tLS0="
-//  }
-type ChannelDef struct {
-	Name        string
-	Description string
-	Salt        []byte
-	PubKey      []byte
-}
-
-// BroadcastMessage is the bindings representation of a broadcast message.
-//
-// Example JSON:
-//  {"RoundID":42,
-//   "EphID":[0,0,0,0,0,0,24,61],
-//   "Payload":"SGVsbG8sIGJyb2FkY2FzdCBmcmllbmRzIQ=="
-//  }
-type BroadcastMessage struct {
-	BroadcastReport
-	Payload []byte
-}
-
-// BroadcastReport is the bindings representation of the info on how a broadcast message was sent
-//
-// Example JSON:
-//  {"RoundID":42,
-//   "EphID":[0,0,0,0,0,0,24,61]
-//  }
-type BroadcastReport struct {
-	RoundsList
-	EphID ephemeral.Id
-}
-
-// BroadcastListener is the public function type bindings can use to listen for
-// broadcast messages.
-//
-// Parameters:
-//  - []byte - the JSON marshalled bytes of the BroadcastMessage object, which
-//    can be passed into WaitForRoundResult to see if the broadcast succeeded.
-type BroadcastListener interface {
-	Callback([]byte, error)
-}
-
-// NewBroadcastChannel creates a bindings-layer broadcast channel & starts listening for new messages
-//
-// Parameters:
-//  - cmixId - internal ID of cmix
-//  - channelDefinition - JSON marshalled ChannelDef object
-func NewBroadcastChannel(cmixId int, channelDefinition []byte) (*Channel, error) {
-	c, err := cmixTrackerSingleton.get(cmixId)
-	if err != nil {
-		return nil, err
-	}
-
-	def := &ChannelDef{}
-	err = json.Unmarshal(channelDefinition, def)
-	if err != nil {
-		return nil, errors.WithMessage(err, "Failed to unmarshal underlying channel definition")
-	}
-
-	channelID, err := cryptoBroadcast.NewChannelID(def.Name, def.Description, def.Salt, def.PubKey)
-	if err != nil {
-		return nil, errors.WithMessage(err, "Failed to generate channel ID")
-	}
-	chanPubLoaded, err := rsa.LoadPublicKeyFromPem(def.PubKey)
-	if err != nil {
-		return nil, errors.WithMessage(err, "Failed to load public key")
-	}
-
-	ch, err := broadcast.NewBroadcastChannel(cryptoBroadcast.Channel{
-		ReceptionID: channelID,
-		Name:        def.Name,
-		Description: def.Description,
-		Salt:        def.Salt,
-		RsaPubKey:   chanPubLoaded,
-	}, c.api.GetCmix(), c.api.GetRng())
-	if err != nil {
-		return nil, errors.WithMessage(err, "Failed to create broadcast channel client")
-	}
-
-	return &Channel{ch: ch}, nil
-}
-
-// Listen registers a BroadcastListener for a given method.
-// This allows users to handle incoming broadcast messages.
-//
-// Parameters:
-//  - l - BroadcastListener object
-//  - method - int corresponding to broadcast.Method constant, 0 for symmetric
-//    or 1 for asymmetric
-func (c *Channel) Listen(l BroadcastListener, method int) error {
-	broadcastMethod := broadcast.Method(method)
-	listen := func(payload []byte,
-		receptionID receptionID.EphemeralIdentity, round rounds.Round) {
-		l.Callback(json.Marshal(&BroadcastMessage{
-			BroadcastReport: BroadcastReport{
-				RoundsList: makeRoundsList(round.ID),
-				EphID:      receptionID.EphId,
-			},
-			Payload: payload,
-		}))
-	}
-	return c.ch.RegisterListener(listen, broadcastMethod)
-}
-
-// Broadcast sends a given payload over the broadcast channel using symmetric
-// broadcast.
-//
-// Returns:
-//  - []byte - the JSON marshalled bytes of the BroadcastReport object, which
-//    can be passed into WaitForRoundResult to see if the broadcast succeeded.
-func (c *Channel) Broadcast(payload []byte) ([]byte, error) {
-	rid, eid, err := c.ch.Broadcast(payload, cmix.GetDefaultCMIXParams())
-	if err != nil {
-		return nil, err
-	}
-	return json.Marshal(BroadcastReport{
-		RoundsList: makeRoundsList(rid),
-		EphID:      eid,
-	})
-}
-
-// BroadcastAsymmetric sends a given payload over the broadcast channel using
-// asymmetric broadcast. This mode of encryption requires a private key.
-//
-// Returns:
-//  - []byte - the JSON marshalled bytes of the BroadcastReport object, which
-//    can be passed into WaitForRoundResult to see if the broadcast succeeded.
-func (c *Channel) BroadcastAsymmetric(payload, pk []byte) ([]byte, error) {
-	pkLoaded, err := rsa.LoadPrivateKeyFromPem(pk)
-	if err != nil {
-		return nil, err
-	}
-	rid, eid, err := c.ch.BroadcastAsymmetric(pkLoaded, payload, cmix.GetDefaultCMIXParams())
-	if err != nil {
-		return nil, err
-	}
-	return json.Marshal(BroadcastReport{
-		RoundsList: makeRoundsList(rid),
-		EphID:      eid,
-	})
-}
-
-// MaxPayloadSize returns the maximum possible payload size which can be broadcast.
-func (c *Channel) MaxPayloadSize() int {
-	return c.ch.MaxPayloadSize()
-}
-
-// MaxAsymmetricPayloadSize returns the maximum possible payload size which can be broadcast.
-func (c *Channel) MaxAsymmetricPayloadSize() int {
-	return c.ch.MaxAsymmetricPayloadSize()
-}
-
-// Get returns the result of calling json.Marshal on a ChannelDef based on the underlying crypto broadcast.Channel.
-func (c *Channel) Get() ([]byte, error) {
-	def := c.ch.Get()
-	return json.Marshal(&ChannelDef{
-		Name:        def.Name,
-		Description: def.Description,
-		Salt:        def.Salt,
-		PubKey:      rsa.CreatePublicKeyPem(def.RsaPubKey),
-	})
-}
-
-// Stop stops the channel from listening for more messages.
-func (c *Channel) Stop() {
-	c.ch.Stop()
-}
diff --git a/bindings/broadcast_test.go b/bindings/broadcast_test.go
deleted file mode 100644
index 5c12dff82a86193ab99cc839d57dc5d94ce93c1a..0000000000000000000000000000000000000000
--- a/bindings/broadcast_test.go
+++ /dev/null
@@ -1,68 +0,0 @@
-package bindings
-
-import (
-	"encoding/json"
-	"gitlab.com/elixxir/crypto/cmix"
-	"gitlab.com/xx_network/crypto/csprng"
-	"gitlab.com/xx_network/crypto/signature/rsa"
-	"gitlab.com/xx_network/primitives/id"
-	"gitlab.com/xx_network/primitives/id/ephemeral"
-	"testing"
-	"time"
-)
-
-func TestChannelDef_JSON(t *testing.T) {
-	rng := csprng.NewSystemRNG()
-	rng.SetSeed([]byte("rng"))
-	pk, _ := rsa.GenerateKey(rng, 256)
-	cd := ChannelDef{
-		Name:        "My broadcast channel",
-		Description: "A broadcast channel for me to test things",
-		Salt:        cmix.NewSalt(rng, 16),
-		PubKey:      rsa.CreatePublicKeyPem(pk.GetPublic()),
-	}
-
-	cdJson, err := json.Marshal(cd)
-	if err != nil {
-		t.Errorf("Failed to marshal channel def: %+v", err)
-	}
-	t.Log(string(cdJson))
-}
-
-func TestBroadcastMessage_JSON(t *testing.T) {
-	uid := id.NewIdFromString("zezima", id.User, t)
-	eid, _, _, err := ephemeral.GetId(uid, 16, time.Now().UnixNano())
-	if err != nil {
-		t.Errorf("Failed to form ephemeral ID: %+v", err)
-	}
-	bm := BroadcastMessage{
-		BroadcastReport: BroadcastReport{
-			RoundsList: makeRoundsList(42),
-			EphID:      eid,
-		},
-		Payload: []byte("Hello, broadcast friends!"),
-	}
-	bmJson, err := json.Marshal(bm)
-	if err != nil {
-		t.Errorf("Failed to marshal broadcast message: %+v", err)
-	}
-	t.Log(string(bmJson))
-}
-
-func TestBroadcastReport_JSON(t *testing.T) {
-	uid := id.NewIdFromString("zezima", id.User, t)
-	eid, _, _, err := ephemeral.GetId(uid, 16, time.Now().UnixNano())
-	if err != nil {
-		t.Errorf("Failed to form ephemeral ID: %+v", err)
-	}
-	br := BroadcastReport{
-		RoundsList: makeRoundsList(42),
-		EphID:      eid,
-	}
-
-	brJson, err := json.Marshal(br)
-	if err != nil {
-		t.Errorf("Failed to marshal broadcast report: %+v", err)
-	}
-	t.Log(string(brJson))
-}
diff --git a/bindings/channels.go b/bindings/channels.go
new file mode 100644
index 0000000000000000000000000000000000000000..78525cf20f8a7a9afe0773f65868b443a5e6d4a0
--- /dev/null
+++ b/bindings/channels.go
@@ -0,0 +1,1160 @@
+///////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx network SEZC                                          //
+//                                                                           //
+// Use of this source code is governed by a license that can be found in the //
+// LICENSE file                                                              //
+///////////////////////////////////////////////////////////////////////////////
+
+package bindings
+
+import (
+	"encoding/json"
+	"github.com/pkg/errors"
+	jww "github.com/spf13/jwalterweatherman"
+	"gitlab.com/elixxir/client/channels"
+	"gitlab.com/elixxir/client/cmix/rounds"
+	"gitlab.com/elixxir/client/xxdk"
+	cryptoBroadcast "gitlab.com/elixxir/crypto/broadcast"
+	cryptoChannel "gitlab.com/elixxir/crypto/channel"
+	"gitlab.com/elixxir/crypto/rsa"
+	"gitlab.com/xx_network/primitives/id"
+	"gitlab.com/xx_network/primitives/id/ephemeral"
+	"sync"
+	"time"
+)
+
+////////////////////////////////////////////////////////////////////////////////
+// Singleton Tracker                                                          //
+////////////////////////////////////////////////////////////////////////////////
+
+// channelManagerTrackerSingleton is used to track ChannelsManager objects
+// so that they can be referenced by ID back over the bindings.
+var channelManagerTrackerSingleton = &channelManagerTracker{
+	tracked: make(map[int]*ChannelsManager),
+	count:   0,
+}
+
+// channelManagerTracker is a singleton used to keep track of extant
+// ChannelsManager objects, preventing race conditions created by passing it
+// over the bindings.
+type channelManagerTracker struct {
+	tracked map[int]*ChannelsManager
+	count   int
+	mux     sync.RWMutex
+}
+
+// make create a ChannelsManager from an [channels.Manager], assigns it a unique
+// ID, and adds it to the channelManagerTracker.
+func (cmt *channelManagerTracker) make(c channels.Manager) *ChannelsManager {
+	cmt.mux.Lock()
+	defer cmt.mux.Unlock()
+
+	chID := cmt.count
+	cmt.count++
+
+	cmt.tracked[chID] = &ChannelsManager{
+		api: c,
+		id:  chID,
+	}
+
+	return cmt.tracked[chID]
+}
+
+// get an ChannelsManager from the channelManagerTracker given its ID.
+func (cmt *channelManagerTracker) get(id int) (*ChannelsManager, error) {
+	cmt.mux.RLock()
+	defer cmt.mux.RUnlock()
+
+	c, exist := cmt.tracked[id]
+	if !exist {
+		return nil, errors.Errorf(
+			"Cannot get ChannelsManager for ID %d, does not exist", id)
+	}
+
+	return c, nil
+}
+
+// delete removes a ChannelsManager from the channelManagerTracker.
+func (cmt *channelManagerTracker) delete(id int) {
+	cmt.mux.Lock()
+	defer cmt.mux.Unlock()
+
+	delete(cmt.tracked, id)
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Basic Channel API                                                          //
+////////////////////////////////////////////////////////////////////////////////
+
+// ChannelsManager is a bindings-layer struct that wraps a [channels.Manager]
+// interface.
+type ChannelsManager struct {
+	api channels.Manager
+	id  int
+}
+
+// GetID returns the channelManagerTracker ID for the ChannelsManager object.
+func (cm *ChannelsManager) GetID() int {
+	return cm.id
+}
+
+// GenerateChannelIdentity creates a new private channel identity
+// ([channel.PrivateIdentity]). The public component can be retrieved as JSON
+// via [GetPublicChannelIdentityFromPrivate].
+//
+// Parameters:
+//  - cmixID - The tracked cmix object ID. This can be retrieved using
+//    [Cmix.GetID].
+//
+// Returns:
+//  - JSON of [channel.PrivateIdentity].
+func GenerateChannelIdentity(cmixID int) ([]byte, error) {
+	// Get user from singleton
+	user, err := cmixTrackerSingleton.get(cmixID)
+	if err != nil {
+		return nil, err
+	}
+
+	rng := user.api.GetRng().GetStream()
+	defer rng.Close()
+	pi, err := cryptoChannel.GenerateIdentity(rng)
+	if err != nil {
+		return nil, err
+	}
+	return pi.Marshal(), nil
+}
+
+// GetPublicChannelIdentity constructs a public identity ([channel.Identity])
+// from a bytes version and returns it JSON marshaled.
+//
+// Parameters:
+//  - marshaledPublic - Bytes of the public identity ([channel.Identity]).
+//
+// Returns:
+//  - JSON of the constructed [channel.Identity].
+func GetPublicChannelIdentity(marshaledPublic []byte) ([]byte, error) {
+	i, err := cryptoChannel.UnmarshalIdentity(marshaledPublic)
+	if err != nil {
+		return nil, err
+	}
+	return json.Marshal(&i)
+}
+
+// GetPublicChannelIdentityFromPrivate returns the public identity
+// ([channel.Identity]) contained in the given private identity
+// ([channel.PrivateIdentity]).
+//
+// Parameters:
+//  - marshaledPrivate - Bytes of the private identity
+//    (channel.PrivateIdentity]).
+//
+// Returns:
+//  - JSON of the public [channel.Identity].
+func GetPublicChannelIdentityFromPrivate(marshaledPrivate []byte) ([]byte, error) {
+	pi, err := cryptoChannel.UnmarshalPrivateIdentity(marshaledPrivate)
+	if err != nil {
+		return nil, err
+	}
+	return json.Marshal(&pi.Identity)
+}
+
+// NewChannelsManagerGoEventModel creates a new [ChannelsManager] from a new
+// private identity ([channel.PrivateIdentity]). This is not compatible with
+// GoMobile Bindings because it receives the go event model.
+//
+// This is for creating a manager for an identity for the first time. For
+// generating a new one channel identity, use [GenerateChannelIdentity]. To
+// reload this channel manager, use [LoadChannelsManagerGoEventModel], passing
+// in the storage tag retrieved by [ChannelsManager.GetStorageTag].
+//
+// Parameters:
+//  - cmixID - The tracked Cmix object ID. This can be retrieved using
+//    [Cmix.GetID].
+//  - privateIdentity - Bytes of a private identity ([channel.PrivateIdentity])
+//    that is generated by [GenerateChannelIdentity].
+//  - goEvent - A function that initialises and returns the event model that is
+//    not compatible with GoMobile bindings.
+func NewChannelsManagerGoEventModel(cmixID int, privateIdentity []byte,
+	goEventBuilder channels.EventModelBuilder) (*ChannelsManager, error) {
+	pi, err := cryptoChannel.UnmarshalPrivateIdentity(privateIdentity)
+	if err != nil {
+		return nil, err
+	}
+
+	// Get user from singleton
+	user, err := cmixTrackerSingleton.get(cmixID)
+	if err != nil {
+		return nil, err
+	}
+
+	// Construct new channels manager
+	m, err := channels.NewManager(pi, user.api.GetStorage().GetKV(),
+		user.api.GetCmix(), user.api.GetRng(), goEventBuilder)
+	if err != nil {
+		return nil, err
+	}
+
+	// Add channel to singleton and return
+	return channelManagerTrackerSingleton.make(m), nil
+}
+
+// LoadChannelsManagerGoEventModel loads an existing ChannelsManager. This is not
+// compatible with GoMobile Bindings because it receives the go event model.
+// This is for creating a manager for an identity for the first time.
+// The channel manager should have first been created with
+// NewChannelsManagerGoEventModel and then the storage tag can be retrieved
+// with ChannelsManager.GetStorageTag
+//
+// Parameters:
+//  - cmixID - The tracked cmix object ID. This can be retrieved using
+//    [Cmix.GetID].
+//  - storageTag - retrieved with ChannelsManager.GetStorageTag
+//  - goEvent - A function that initialises and returns the event model that is
+//    not compatible with GoMobile bindings.
+func LoadChannelsManagerGoEventModel(cmixID int, storageTag string,
+	goEventBuilder channels.EventModelBuilder) (*ChannelsManager, error) {
+
+	// Get user from singleton
+	user, err := cmixTrackerSingleton.get(cmixID)
+	if err != nil {
+		return nil, err
+	}
+
+	// Construct new channels manager
+	m, err := channels.LoadManager(storageTag, user.api.GetStorage().GetKV(),
+		user.api.GetCmix(), user.api.GetRng(), goEventBuilder)
+	if err != nil {
+		return nil, err
+	}
+
+	// Add channel to singleton and return
+	return channelManagerTrackerSingleton.make(m), nil
+}
+
+// NewChannelsManager creates a new [ChannelsManager] from a new private
+// identity ([channel.PrivateIdentity]).
+//
+// This is for creating a manager for an identity for the first time. For
+// generating a new one channel identity, use [GenerateChannelIdentity]. To
+// reload this channel manager, use [LoadChannelsManager], passing in the
+// storage tag retrieved by [ChannelsManager.GetStorageTag].
+//
+// Parameters:
+//  - cmixID - The tracked Cmix object ID. This can be retrieved using
+//    [Cmix.GetID].
+//  - privateIdentity - Bytes of a private identity ([channel.PrivateIdentity])
+//    that is generated by [GenerateChannelIdentity].
+//  - event -  An interface that contains a function that initialises and returns
+//    the event model that is bindings-compatible.
+func NewChannelsManager(cmixID int, privateIdentity []byte,
+	eventBuilder EventModelBuilder) (*ChannelsManager, error) {
+	pi, err := cryptoChannel.UnmarshalPrivateIdentity(privateIdentity)
+	if err != nil {
+		return nil, err
+	}
+
+	// Get user from singleton
+	user, err := cmixTrackerSingleton.get(cmixID)
+	if err != nil {
+		return nil, err
+	}
+
+	eb := func(path string) (channels.EventModel, error) {
+		return NewEventModel(eventBuilder.Build(path)), nil
+	}
+
+	// Construct new channels manager
+	m, err := channels.NewManager(pi, user.api.GetStorage().GetKV(),
+		user.api.GetCmix(), user.api.GetRng(), eb)
+	if err != nil {
+		return nil, err
+	}
+
+	// Add channel to singleton and return
+	return channelManagerTrackerSingleton.make(m), nil
+}
+
+// LoadChannelsManager loads an existing [ChannelsManager].
+//
+// This is for loading a manager for an identity that has already been created.
+// The channel manager should have previously been created with
+// [NewChannelsManager] and the storage is retrievable with
+// [ChannelsManager.GetStorageTag].
+//
+// Parameters:
+//  - cmixID - The tracked cmix object ID. This can be retrieved using
+//    [Cmix.GetID].
+//  - storageTag - The storage tag associated with the previously created
+//    channel manager and retrieved with [ChannelsManager.GetStorageTag].
+//  - event - An interface that contains a function that initialises and returns
+//    the event model that is bindings-compatible.
+func LoadChannelsManager(cmixID int, storageTag string,
+	eventBuilder EventModelBuilder) (*ChannelsManager, error) {
+
+	// Get user from singleton
+	user, err := cmixTrackerSingleton.get(cmixID)
+	if err != nil {
+		return nil, err
+	}
+
+	eb := func(path string) (channels.EventModel, error) {
+		return NewEventModel(eventBuilder.Build(path)), nil
+	}
+
+	// Construct new channels manager
+	m, err := channels.LoadManager(storageTag, user.api.GetStorage().GetKV(),
+		user.api.GetCmix(), user.api.GetRng(), eb)
+	if err != nil {
+		return nil, err
+	}
+
+	// Add channel to singleton and return
+	return channelManagerTrackerSingleton.make(m), nil
+}
+
+type ChannelGeneration struct {
+	Channel    string
+	PrivateKey string
+}
+
+// GenerateChannel is used to create a channel a new channel of which you are
+// the admin. It is only for making new channels, not joining existing ones.
+//
+// It returns a pretty print of the channel and the private key.
+//
+// The name cannot be longer that __ characters. The description cannot be
+// longer than __ and can only use ______ characters.
+//
+// Parameters:
+//  - cmixID - The tracked cmix object ID. This can be retrieved using
+//    [Cmix.GetID].
+//  - name - The name of the new channel. The name cannot be longer than __
+//    characters and must contain only _____ characters. It cannot be changed
+//    once a channel is created.
+//  - description - The description of a channel. The description cannot be
+//    longer than __ characters and must contain only _____ characters. It
+//    cannot be changed once a channel is created.
+//
+// Returns:
+//  - []byte - ChannelGeneration describes a generated channel. It contains both
+//    the public channel info and the private key for the channel in PEM format.
+//    fixme: document json
+func GenerateChannel(cmixID int, name, description string) ([]byte, error) {
+	// Get cmix from singleton so its rng can be used
+	cmix, err := cmixTrackerSingleton.get(cmixID)
+	if err != nil {
+		return nil, err
+	}
+
+	stream := cmix.api.GetRng().GetStream()
+	defer stream.Close()
+	c, pk, err := cryptoBroadcast.NewChannel(
+		name, description, cmix.api.GetCmix().GetMaxMessageLength(), stream)
+	if err != nil {
+		return nil, err
+	}
+
+	gen := ChannelGeneration{
+		Channel:    c.PrettyPrint(),
+		PrivateKey: string(pk.MarshalPem()),
+	}
+
+	return json.Marshal(&gen)
+}
+
+type ChannelInfo struct {
+	Name        string
+	Description string
+	ChannelID   string
+}
+
+// GetChannelInfo returns the info about a channel from its public description.
+//
+// Parameters:
+//  - prettyPrint - The pretty print of the channel.
+//
+// The pretty print will be of the format:
+//  <XXChannel-v1:Test Channel,description:This is a test channel,secrets:pn0kIs6P1pHvAe7u8kUyf33GYVKmkoCX9LhCtvKJZQI=,3A5eB5pzSHyxN09w1kOVrTIEr5UyBbzmmd9Ga5Dx0XA=,0,0,/zChIlLr2p3Vsm2X4+3TiFapoapaTi8EJIisJSqwfGc=>
+//
+// Returns:
+//  - []byte - ChannelInfo describes all relevant channel info.
+//    fixme: document json
+func GetChannelInfo(prettyPrint string) ([]byte, error) {
+	_, bytes, err := getChannelInfo(prettyPrint)
+	return bytes, err
+}
+
+func getChannelInfo(prettyPrint string) (*cryptoBroadcast.Channel, []byte, error) {
+	c, err := cryptoBroadcast.NewChannelFromPrettyPrint(prettyPrint)
+	if err != nil {
+		return nil, nil, err
+	}
+	ci := &ChannelInfo{
+		Name:        c.Name,
+		Description: c.Description,
+		ChannelID:   c.ReceptionID.String(),
+	}
+	bytes, err := json.Marshal(ci)
+	if err != nil {
+		return nil, nil, err
+	}
+	return c, bytes, nil
+}
+
+// JoinChannel joins the given channel. It will fail if the channel has already
+// been joined.
+//
+// Parameters:
+//  - channelPretty - A portable channel string. Should be received from
+//    another user or generated via GenerateChannel.
+//
+// The pretty print will be of the format:
+//  <XXChannel-v1:Test Channel,description:This is a test channel,secrets:pn0kIs6P1pHvAe7u8kUyf33GYVKmkoCX9LhCtvKJZQI=,3A5eB5pzSHyxN09w1kOVrTIEr5UyBbzmmd9Ga5Dx0XA=,0,0,/zChIlLr2p3Vsm2X4+3TiFapoapaTi8EJIisJSqwfGc=>"
+//
+// Returns:
+//  - []byte - ChannelInfo describes all relevant channel info.
+//    fixme: document json
+func (cm *ChannelsManager) JoinChannel(channelPretty string) ([]byte, error) {
+	c, info, err := getChannelInfo(channelPretty)
+	if err != nil {
+		return nil, err
+	}
+
+	// Join the channel using the API
+	err = cm.api.JoinChannel(c)
+
+	return info, err
+}
+
+// GetChannels returns the IDs of all channels that have been joined.
+//
+// Returns:
+//  - []byte - A JSON marshalled list of IDs.
+//
+// JSON Example:
+//  {
+//    "U4x/lrFkvxuXu59LtHLon1sUhPJSCcnZND6SugndnVID",
+//    "15tNdkKbYXoMn58NO6VbDMDWFEyIhTWEGsvgcJsHWAgD"
+//  }
+func (cm *ChannelsManager) GetChannels() ([]byte, error) {
+	channelIds := cm.api.GetChannels()
+	return json.Marshal(channelIds)
+}
+
+// LeaveChannel leaves the given channel. It will return an error if the
+// channel was not previously joined.
+//
+// Parameters:
+//  - marshalledChanId - A JSON marshalled channel ID ([id.ID]).
+func (cm *ChannelsManager) LeaveChannel(marshalledChanId []byte) error {
+	// Unmarshal channel ID
+	channelId, err := id.Unmarshal(marshalledChanId)
+	if err != nil {
+		return err
+	}
+
+	// Leave the channel
+	return cm.api.LeaveChannel(channelId)
+}
+
+// ReplayChannel replays all messages from the channel within the network's
+// memory (~3 weeks) over the event model.
+//
+// Parameters:
+//  - marshalledChanId - A JSON marshalled channel ID ([id.ID]).
+func (cm *ChannelsManager) ReplayChannel(marshalledChanId []byte) error {
+
+	// Unmarshal channel ID
+	chanId, err := id.Unmarshal(marshalledChanId)
+	if err != nil {
+		return err
+	}
+
+	// Replay channel
+	return cm.api.ReplayChannel(chanId)
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Channel Sending Methods & Reports                                          //
+////////////////////////////////////////////////////////////////////////////////
+
+// ChannelSendReport is the bindings' representation of the return values of
+// ChannelsManager's Send operations.
+//
+// JSON Example:
+//  {
+//    "MessageId": "0kitNxoFdsF4q1VMSI/xPzfCnGB2l+ln2+7CTHjHbJw=",
+//    "Rounds":[1,5,9],
+//    "EphId": 0
+//  }
+type ChannelSendReport struct {
+	MessageId []byte
+	RoundsList
+	EphId int64
+}
+
+// SendGeneric is used to send a raw message over a channel. In general, it
+// should be wrapped in a function that defines the wire protocol. If the final
+// message, before being sent over the wire, is too long, this will return an
+// error. Due to the underlying encoding using compression, it isn't possible to
+// define the largest payload that can be sent, but it will always be possible
+// to send a payload of 802 bytes at minimum. The meaning of validUntil depends
+// on the use case.
+//
+// Parameters:
+//  - marshalledChanId - A JSON marshalled channel ID ([id.ID]).
+//  - messageType - The message type of the message. This will be a valid
+//    [channels.MessageType].
+//  - message - The contents of the message. This need not be of data type
+//    string, as the message could be a specified format that the channel may
+//    recognize.
+//  - leaseTimeMS - The lease of the message. This will be how long the message
+//    is valid until, in milliseconds. As per the channels.Manager
+//    documentation, this has different meanings depending on the use case.
+//    These use cases may be generic enough that they will not be enumerated
+//    here.
+//  - cmixParamsJSON - A JSON marshalled [xxdk.CMIXParams]. This may be empty,
+//    and GetDefaultCMixParams will be used internally.
+//
+// Returns:
+//  - []byte - A JSON marshalled ChannelSendReport.
+func (cm *ChannelsManager) SendGeneric(marshalledChanId []byte,
+	messageType int, message []byte, leaseTimeMS int64,
+	cmixParamsJSON []byte) ([]byte, error) {
+
+	// Unmarshal channel ID and parameters
+	chanId, params, err := parseChannelsParameters(
+		marshalledChanId, cmixParamsJSON)
+	if err != nil {
+		return nil, err
+	}
+
+	// Send message
+	chanMsgId, rnd, ephId, err := cm.api.SendGeneric(chanId,
+		channels.MessageType(messageType), message,
+		time.Duration(leaseTimeMS), params.CMIX)
+	if err != nil {
+		return nil, err
+	}
+
+	// Construct send report
+	return constructChannelSendReport(chanMsgId, rnd.ID, ephId)
+}
+
+// SendAdminGeneric is used to send a raw message over a channel encrypted with
+// admin keys, identifying it as sent by the admin. In general, it should be
+// wrapped in a function that defines the wire protocol. If the final message,
+// before being sent over the wire, is too long, this will return an error. The
+// message must be at most 510 bytes long.
+//
+// Parameters:
+//  - adminPrivateKey - The PEM-encoded admin RSA private key.
+//  - marshalledChanId - A JSON marshalled channel ID ([id.ID]).
+//  - messageType - The message type of the message. This will be a valid
+//    [channels.MessageType].
+//  - message - The contents of the message. The message should be at most 510
+//    bytes. This need not be of data type string, as the message could be a
+//    specified format that the channel may recognize.
+//  - leaseTimeMS - The lease of the message. This will be how long the message
+//    is valid until, in milliseconds. As per the channels.Manager
+//    documentation, this has different meanings depending on the use case.
+//    These use cases may be generic enough that they will not be enumerated
+//    here.
+//  - cmixParamsJSON - A JSON marshalled [xxdk.CMIXParams]. This may be empty,
+//    and GetDefaultCMixParams will be used internally.
+//
+// Returns:
+//  - []byte - A JSON marshalled ChannelSendReport.
+func (cm *ChannelsManager) SendAdminGeneric(adminPrivateKey,
+	marshalledChanId []byte,
+	messageType int, message []byte, leaseTimeMS int64,
+	cmixParamsJSON []byte) ([]byte, error) {
+
+	// Load private key from file
+	rsaPrivKey, err := rsa.GetScheme().UnmarshalPrivateKeyPEM(adminPrivateKey)
+	if err != nil {
+		return nil, err
+	}
+
+	// Unmarshal channel ID and parameters
+	chanId, params, err := parseChannelsParameters(
+		marshalledChanId, cmixParamsJSON)
+	if err != nil {
+		return nil, err
+	}
+
+	// Send admin message
+	chanMsgId, rnd, ephId, err := cm.api.SendAdminGeneric(rsaPrivKey,
+		chanId, channels.MessageType(messageType), message,
+		time.Duration(leaseTimeMS), params.CMIX)
+
+	// Construct send report
+	return constructChannelSendReport(chanMsgId, rnd.ID, ephId)
+}
+
+// SendMessage is used to send a formatted message over a channel.
+// Due to the underlying encoding using compression, it isn't possible to define
+// the largest payload that can be sent, but it will always be possible to send
+// a payload of 798 bytes at minimum.
+//
+// The message will auto delete validUntil after the round it is sent in,
+// lasting forever if [channels.ValidForever] is used.
+//
+// Parameters:
+//  - marshalledChanId - A JSON marshalled channel ID ([id.ID]).
+//  - message - The contents of the message. The message should be at most 510
+//    bytes. This is expected to be Unicode, and thus a string data type is
+//    expected
+//  - leaseTimeMS - The lease of the message. This will be how long the message
+//    is valid until, in milliseconds. As per the channels.Manager
+//    documentation, this has different meanings depending on the use case.
+//    These use cases may be generic enough that they will not be enumerated
+//    here.
+//  - cmixParamsJSON - A JSON marshalled [xxdk.CMIXParams]. This may be
+//    empty, and GetDefaultCMixParams will be used internally.
+//
+// Returns:
+//  - []byte - A JSON marshalled ChannelSendReport
+func (cm *ChannelsManager) SendMessage(marshalledChanId []byte,
+	message string, leaseTimeMS int64, cmixParamsJSON []byte) ([]byte, error) {
+
+	// Unmarshal channel ID and parameters
+	chanId, params, err := parseChannelsParameters(
+		marshalledChanId, cmixParamsJSON)
+	if err != nil {
+		return nil, err
+	}
+
+	// Send message
+	chanMsgId, rnd, ephId, err := cm.api.SendMessage(chanId, message,
+		time.Duration(leaseTimeMS), params.CMIX)
+	if err != nil {
+		return nil, err
+	}
+
+	// Construct send report
+	return constructChannelSendReport(chanMsgId, rnd.ID, ephId)
+}
+
+// SendReply is used to send a formatted message over a channel. Due to the
+// underlying encoding using compression, it isn't possible to define the
+// largest payload that can be sent, but it will always be possible to send a
+// payload of 766 bytes at minimum.
+//
+// If the message ID the reply is sent to is nonexistent, the other side will
+// post the message as a normal message and not a reply. The message will auto
+// delete validUntil after the round it is sent in, lasting forever if
+// [channels.ValidForever] is used.
+//
+// Parameters:
+//  - marshalledChanId - A JSON marshalled channel ID ([id.ID]).
+//  - message - The contents of the message. The message should be at most 510
+//    bytes. This is expected to be Unicode, and thus a string data type is
+//    expected.
+//  - messageToReactTo - The marshalled [channel.MessageID] of the message you
+//    wish to reply to. This may be found in the ChannelSendReport if replying
+//    to your own. Alternatively, if reacting to another user's message, you may
+//    retrieve it via the ChannelMessageReceptionCallback registered using
+//    RegisterReceiveHandler.
+//  - leaseTimeMS - The lease of the message. This will be how long the message
+//    is valid until, in milliseconds. As per the channels.Manager
+//    documentation, this has different meanings depending on the use case.
+//    These use cases may be generic enough that they will not be enumerated
+//    here.
+//  - cmixParamsJSON - A JSON marshalled [xxdk.CMIXParams]. This may be empty,
+//    and GetDefaultCMixParams will be used internally.
+//
+// Returns:
+//  - []byte - A JSON marshalled ChannelSendReport
+func (cm *ChannelsManager) SendReply(marshalledChanId []byte,
+	message string, messageToReactTo []byte, leaseTimeMS int64,
+	cmixParamsJSON []byte) ([]byte, error) {
+
+	// Unmarshal channel ID and parameters
+	chanId, params, err := parseChannelsParameters(
+		marshalledChanId, cmixParamsJSON)
+	if err != nil {
+		return nil, err
+	}
+
+	// Unmarshal message ID
+	msgId := cryptoChannel.MessageID{}
+	copy(msgId[:], messageToReactTo)
+
+	// Send Reply
+	chanMsgId, rnd, ephId, err := cm.api.SendReply(chanId, message,
+		msgId, time.Duration(leaseTimeMS), params.CMIX)
+	if err != nil {
+		return nil, err
+	}
+
+	// Construct send report
+	return constructChannelSendReport(chanMsgId, rnd.ID, ephId)
+}
+
+// SendReaction is used to send a reaction to a message over a channel.
+// The reaction must be a single emoji with no other characters, and will
+// be rejected otherwise.
+// Users will drop the reaction if they do not recognize the reactTo message.
+//
+// Parameters:
+//  - marshalledChanId - A JSON marshalled channel ID ([id.ID]).
+//  - reaction - The user's reaction. This should be a single emoji with no
+//    other characters. As such, a Unicode string is expected.
+//  - messageToReactTo - The marshalled [channel.MessageID] of the message you
+//    wish to reply to. This may be found in the ChannelSendReport if replying
+//    to your own. Alternatively, if reacting to another user's message, you may
+//    retrieve it via the ChannelMessageReceptionCallback registered using
+//    RegisterReceiveHandler.
+//  - cmixParamsJSON - A JSON marshalled [xxdk.CMIXParams]. This may be empty,
+//  and GetDefaultCMixParams will be used internally.
+//
+// Returns:
+//  - []byte - A JSON marshalled ChannelSendReport.
+func (cm *ChannelsManager) SendReaction(marshalledChanId []byte,
+	reaction string, messageToReactTo []byte,
+	cmixParamsJSON []byte) ([]byte, error) {
+
+	// Unmarshal channel ID and parameters
+	chanId, params, err := parseChannelsParameters(
+		marshalledChanId, cmixParamsJSON)
+	if err != nil {
+		return nil, err
+	}
+
+	// Unmarshal message ID
+	msgId := cryptoChannel.MessageID{}
+	copy(msgId[:], messageToReactTo)
+
+	// Send reaction
+	chanMsgId, rnd, ephId, err := cm.api.SendReaction(chanId,
+		reaction, msgId, params.CMIX)
+	if err != nil {
+		return nil, err
+	}
+
+	// Construct send report
+	return constructChannelSendReport(chanMsgId, rnd.ID, ephId)
+}
+
+// GetIdentity returns the marshaled public identity ([channel.Identity]) that
+// the channel is using.
+func (cm *ChannelsManager) GetIdentity() ([]byte, error) {
+	i := cm.api.GetIdentity()
+	return json.Marshal(&i)
+}
+
+// GetStorageTag returns the storage tag needed to reload the manager.
+func (cm *ChannelsManager) GetStorageTag() string {
+	return cm.api.GetStorageTag()
+}
+
+// SetNickname sets the nickname for a given channel. The nickname must be valid
+// according to [IsNicknameValid].
+func (cm *ChannelsManager) SetNickname(newNick string, ch []byte) error {
+	chid, err := id.Unmarshal(ch)
+	if err != nil {
+		return err
+	}
+	return cm.api.SetNickname(newNick, chid)
+}
+
+// DeleteNickname deletes the nickname for a given channel.
+func (cm *ChannelsManager) DeleteNickname(ch []byte) error {
+	chid, err := id.Unmarshal(ch)
+	if err != nil {
+		return err
+	}
+	return cm.api.DeleteNickname(chid)
+}
+
+// GetNickname returns the nickname set for a given channel. Returns an error if
+// there is no nickname set.
+func (cm *ChannelsManager) GetNickname(ch []byte) (string, error) {
+	chid, err := id.Unmarshal(ch)
+	if err != nil {
+		return "", err
+	}
+	nick, exists := cm.api.GetNickname(chid)
+	if !exists {
+		return "", errors.New("no nickname found for the given channel")
+	}
+
+	return nick, nil
+}
+
+// IsNicknameValid checks if a nickname is valid.
+//
+// Rules:
+//  1. A nickname must not be longer than 24 characters.
+//  2. A nickname must not be shorter than 1 character.
+func IsNicknameValid(nick string) error {
+	return channels.IsNicknameValid(nick)
+}
+
+// parseChannelsParameters is a helper function for the Send functions. It
+// parses the channel ID and the passed in parameters into their respective
+// objects. These objects are passed into the API via the internal send
+// functions.
+func parseChannelsParameters(marshalledChanId, cmixParamsJSON []byte) (
+	*id.ID, xxdk.CMIXParams, error) {
+	// Unmarshal channel ID
+	chanId, err := id.Unmarshal(marshalledChanId)
+	if err != nil {
+		return nil, xxdk.CMIXParams{}, err
+	}
+
+	// Unmarshal cmix params
+	params, err := parseCMixParams(cmixParamsJSON)
+	if err != nil {
+		return nil, xxdk.CMIXParams{}, err
+	}
+
+	return chanId, params, nil
+}
+
+// constructChannelSendReport is a helper function which returns a JSON
+// marshalled ChannelSendReport.
+func constructChannelSendReport(channelMessageId cryptoChannel.MessageID,
+	roundId id.Round, ephId ephemeral.Id) ([]byte, error) {
+	// Construct send report
+	chanSendReport := ChannelSendReport{
+		MessageId:  channelMessageId.Bytes(),
+		RoundsList: makeRoundsList(roundId),
+		EphId:      ephId.Int64(),
+	}
+
+	// Marshal send report
+	return json.Marshal(chanSendReport)
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Channel Receiving Logic and Callback Registration                          //
+////////////////////////////////////////////////////////////////////////////////
+
+// ReceivedChannelMessageReport is a report structure returned via the
+// ChannelMessageReceptionCallback. This report gives the context for the
+// channel the message was sent to and the message itself. This is returned via
+// the callback as JSON marshalled bytes.
+//
+// JSON Example:
+//  {
+//    "ChannelId": "AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
+//    "MessageId": "3S6DiVjWH9mLmjy1oaam/3x45bJQzOW6u2KgeUn59wA=",
+//    "ReplyTo":"cxMyGUFJ+Ff1Xp2X+XkIpOnNAQEZmv8SNP5eYH4tCik=",
+//    "MessageType": 42,
+//    "SenderUsername": "hunter2",
+//    "Content": "YmFuX2JhZFVTZXI=",
+//    "Timestamp": 1662502150335283000,
+//    "Lease": 25,
+//    "Rounds": [ 1, 4, 9],
+//  }
+type ReceivedChannelMessageReport struct {
+	ChannelId   []byte
+	MessageId   []byte
+	MessageType int
+	Nickname    string
+	Identity    []byte
+	Content     []byte
+	Timestamp   int64
+	Lease       int64
+	RoundsList
+}
+
+// ChannelMessageReceptionCallback is the callback that returns the context for
+// a channel message via the Callback.
+// It must return a unique UUID for the message by which it can be referenced
+// later
+type ChannelMessageReceptionCallback interface {
+	Callback(receivedChannelMessageReport []byte, err error) int
+}
+
+// RegisterReceiveHandler is used to register handlers for non-default message
+// types. They can be processed by modules. It is important that such modules
+// sync up with the event model implementation.
+//
+// There can only be one handler per [channels.MessageType], and this will
+// return an error on any re-registration.
+//
+// Parameters:
+//  - messageType - represents the [channels.MessageType] which will have a
+//    registered listener.
+//  - listenerCb - the callback which will be executed when a channel message
+//    of messageType is received.
+func (cm *ChannelsManager) RegisterReceiveHandler(messageType int,
+	listenerCb ChannelMessageReceptionCallback) error {
+
+	// Wrap callback around backend interface
+	cb := channels.MessageTypeReceiveMessage(
+		func(channelID *id.ID,
+			messageID cryptoChannel.MessageID, messageType channels.MessageType,
+			nickname string, content []byte, identity cryptoChannel.Identity,
+			timestamp time.Time, lease time.Duration, round rounds.Round,
+			status channels.SentStatus) uint64 {
+
+			idBytes, err := json.Marshal(&identity)
+			if err != nil {
+				jww.WARN.Printf("failed to marshal identity object: %+v", err)
+				return 0
+			}
+
+			rcm := ReceivedChannelMessageReport{
+				ChannelId:   channelID.Marshal(),
+				MessageId:   messageID.Bytes(),
+				MessageType: int(messageType),
+				Nickname:    nickname,
+				Identity:    idBytes,
+				Content:     content,
+				Timestamp:   timestamp.UnixNano(),
+				Lease:       int64(lease),
+				RoundsList:  makeRoundsList(round.ID),
+			}
+
+			return uint64(listenerCb.Callback(json.Marshal(rcm)))
+		})
+
+	// Register handler
+	return cm.api.RegisterReceiveHandler(channels.MessageType(messageType), cb)
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Event Model Logic                                                          //
+////////////////////////////////////////////////////////////////////////////////
+
+// EventModelBuilder builds an event model
+type EventModelBuilder interface {
+	Build(path string) EventModel
+}
+
+// EventModel is an interface which an external party which uses the channels
+// system passed an object which adheres to in order to get events on the
+// channel.
+type EventModel interface {
+	// JoinChannel is called whenever a channel is joined locally.
+	//
+	// Parameters:
+	//  - channel - Returns the pretty print representation of a channel.
+	JoinChannel(channel string)
+
+	// LeaveChannel is called whenever a channel is left locally.
+	//
+	// Parameters:
+	//  - ChannelId - The marshalled channel [id.ID].
+	LeaveChannel(channelID []byte)
+
+	// ReceiveMessage is called whenever a message is received on a given
+	// channel. It may be called multiple times on the same message. It is
+	// incumbent on the user of the API to filter such called by message ID.
+	//
+	// Parameters:
+	//  - channelID - The marshalled channel [id.ID].
+	//  - messageID - The bytes of the [channel.MessageID] of the received
+	//    message.
+	//  - nickname - The nickname of the sender of the message.
+	//  - text - The content of the message.
+	//  - timestamp - Time the message was received; represented as nanoseconds
+	//    since unix epoch.
+	//  - identity - the json of the identity of the sender
+	//  - lease - The number of nanoseconds that the message is valid for.
+	//  - roundId - The ID of the round that the message was received on.
+	//  - mType - the type of the message, always 1 for this call
+	//  - status - the [channels.SentStatus] of the message.
+	//
+	// Statuses will be enumerated as such:
+	//  Sent      =  0
+	//  Delivered =  1
+	//  Failed    =  2
+	//
+	// Returns a non-negative unique UUID for the message that it can be
+	// referenced by later with [EventModel.UpdateSentStatus].
+	ReceiveMessage(channelID, messageID []byte, nickname, text string,
+		identity []byte, timestamp, lease, roundId, mType,
+		status int64) int64
+
+	// ReceiveReply is called whenever a message is received that is a reply on
+	// a given channel. It may be called multiple times on the same message. It
+	// is incumbent on the user of the API to filter such called by message ID.
+	//
+	// Messages may arrive our of order, so a reply in theory can arrive before
+	// the initial message. As a result, it may be important to buffer replies.
+	//
+	// Parameters:
+	//  - channelID - The marshalled channel [id.ID].
+	//  - messageID - The bytes of the [channel.MessageID] of the received
+	//    message.
+	//  - reactionTo - The [channel.MessageID] for the message that received a
+	//    reply.
+	//  - nickname - The nickname of the sender of the message.
+	//  - text - The content of the message.
+	//  - identity - the json marshaled identity of the sender
+	//  - timestamp - Time the message was received; represented as nanoseconds
+	//    since unix epoch.
+	//  - lease - The number of nanoseconds that the message is valid for.
+	//  - roundId - The ID of the round that the message was received on.
+	//  - mType - the type of the message, always 1 for this call
+	//  - status - the [channels.SentStatus] of the message.
+	//
+	// Statuses will be enumerated as such:
+	//  Sent      =  0
+	//  Delivered =  1
+	//  Failed    =  2
+	//
+	// Returns a non-negative unique UUID for the message that it can be
+	// referenced by later with [EventModel.UpdateSentStatus].
+	ReceiveReply(channelID, messageID, reactionTo []byte,
+		nickname, text string, identity []byte,
+		timestamp, lease, roundId, mType, status int64) int64
+
+	// ReceiveReaction is called whenever a reaction to a message is received
+	// on a given channel. It may be called multiple times on the same reaction.
+	// It is incumbent on the user of the API to filter such called by message
+	// ID.
+	//
+	// Messages may arrive our of order, so a reply in theory can arrive before
+	// the initial message. As a result, it may be important to buffer
+	// reactions.
+	//
+	// Parameters:
+	//  - channelID - The marshalled channel [id.ID].
+	//  - messageID - The bytes of the [channel.MessageID] of the received
+	//    message.
+	//  - reactionTo - The [channel.MessageID] for the message that received a
+	//    reply.
+	//  - nickname - The nickname of the sender of the message.
+	//  - reaction - The contents of the reaction message.
+	//  - identity - The json marshal of the identity of the sender
+	//  - timestamp - Time the message was received; represented as nanoseconds
+	//    since unix epoch.
+	//  - lease - The number of nanoseconds that the message is valid for.
+	//  - roundId - The ID of the round that the message was received on.
+	//  - mType - the type of the message, always 1 for this call
+	//  - status - the [channels.SentStatus] of the message.
+	//
+	// Statuses will be enumerated as such:
+	//  Sent      =  0
+	//  Delivered =  1
+	//  Failed    =  2
+	//
+	// Returns a non-negative unique uuid for the message by which it can be
+	// referenced later with UpdateSentStatus
+	ReceiveReaction(channelID, messageID, reactionTo []byte,
+		nickname, reaction string, identity []byte,
+		timestamp, lease, roundId, mtype, status int64) int64
+
+	// UpdateSentStatus is called whenever the sent status of a message has
+	// changed.
+	//
+	// Parameters:
+	//  - messageID - The bytes of the [channel.MessageID] of the received
+	//    message.
+	//  - status - the [channels.SentStatus] of the message.
+	//
+	// Statuses will be enumerated as such:
+	//  Sent      =  0
+	//  Delivered =  1
+	//  Failed    =  2
+	UpdateSentStatus(
+		uuid int64, messageID []byte, timestamp, roundID, status int64)
+
+	// unimplemented
+	// IgnoreMessage(ChannelID *id.ID, MessageID cryptoChannel.MessageID)
+	// UnIgnoreMessage(ChannelID *id.ID, MessageID cryptoChannel.MessageID)
+	// PinMessage(ChannelID *id.ID, MessageID cryptoChannel.MessageID, end time.Time)
+	// UnPinMessage(ChannelID *id.ID, MessageID cryptoChannel.MessageID)
+}
+
+// toEventModel is a wrapper which wraps an existing channels.EventModel object.
+type toEventModel struct {
+	em EventModel
+}
+
+// NewEventModel is a constructor for a toEventModel. This will take in an
+// EventModel and wraps it around the toEventModel.
+func NewEventModel(em EventModel) channels.EventModel {
+	return &toEventModel{em: em}
+}
+
+// JoinChannel is called whenever a channel is joined locally.
+func (tem *toEventModel) JoinChannel(channel *cryptoBroadcast.Channel) {
+	tem.em.JoinChannel(channel.PrettyPrint())
+}
+
+// LeaveChannel is called whenever a channel is left locally.
+func (tem *toEventModel) LeaveChannel(channelID *id.ID) {
+	tem.em.LeaveChannel(channelID[:])
+}
+
+// ReceiveMessage is called whenever a message is received on a given channel.
+// It may be called multiple times on the same message. It is incumbent on the
+// user of the API to filter such called by message ID.
+func (tem *toEventModel) ReceiveMessage(channelID *id.ID, messageID cryptoChannel.MessageID,
+	nickname, text string, identity cryptoChannel.Identity,
+	timestamp time.Time, lease time.Duration, round rounds.Round,
+	mType channels.MessageType,
+	status channels.SentStatus) uint64 {
+
+	idBytes, err := json.Marshal(&identity)
+	if err != nil {
+		jww.WARN.Printf("failed to marshal identity object: %+v", err)
+		return 0
+	}
+
+	return uint64(tem.em.ReceiveMessage(channelID[:], messageID[:], nickname,
+		text, idBytes, timestamp.UnixNano(), int64(lease), int64(round.ID), int64(mType),
+		int64(status)))
+}
+
+// ReceiveReply is called whenever a message is received that is a reply on a
+// given channel. It may be called multiple times on the same message. It is
+// incumbent on the user of the API to filter such called by message ID.
+//
+// Messages may arrive our of order, so a reply in theory can arrive before the
+// initial message. As a result, it may be important to buffer replies.
+func (tem *toEventModel) ReceiveReply(channelID *id.ID, messageID cryptoChannel.MessageID,
+	reactionTo cryptoChannel.MessageID, nickname, text string,
+	identity cryptoChannel.Identity, timestamp time.Time,
+	lease time.Duration, round rounds.Round, mType channels.MessageType,
+	status channels.SentStatus) uint64 {
+
+	idBytes, err := json.Marshal(&identity)
+	if err != nil {
+		jww.WARN.Printf("failed to marshal identity object: %+v", err)
+		return 0
+	}
+
+	return uint64(tem.em.ReceiveReply(channelID[:], messageID[:], reactionTo[:],
+		nickname, text, idBytes, timestamp.UnixNano(), int64(lease),
+		int64(round.ID), int64(mType), int64(status)))
+
+}
+
+// ReceiveReaction is called whenever a reaction to a message is received on a
+// given channel. It may be called multiple times on the same reaction. It is
+// incumbent on the user of the API to filter such called by message ID.
+//
+// Messages may arrive our of order, so a reply in theory can arrive before the
+// initial message. As a result, it may be important to buffer reactions.
+func (tem *toEventModel) ReceiveReaction(channelID *id.ID, messageID cryptoChannel.MessageID,
+	reactionTo cryptoChannel.MessageID, nickname, reaction string,
+	identity cryptoChannel.Identity, timestamp time.Time,
+	lease time.Duration, round rounds.Round, mType channels.MessageType,
+	status channels.SentStatus) uint64 {
+
+	idBytes, err := json.Marshal(&identity)
+	if err != nil {
+		jww.WARN.Printf("failed to marshal identity object: %+v", err)
+		return 0
+	}
+
+	return uint64(tem.em.ReceiveReaction(channelID[:], messageID[:],
+		reactionTo[:], nickname, reaction, idBytes, timestamp.UnixNano(),
+		int64(lease), int64(round.ID), int64(mType), int64(status)))
+}
+
+// UpdateSentStatus is called whenever the sent status of a message has changed.
+func (tem *toEventModel) UpdateSentStatus(uuid uint64,
+	messageID cryptoChannel.MessageID, timestamp time.Time, round rounds.Round,
+	status channels.SentStatus) {
+	tem.em.UpdateSentStatus(int64(uuid), messageID[:], timestamp.UnixNano(),
+		int64(round.ID), int64(status))
+}
diff --git a/bindings/cmix.go b/bindings/cmix.go
index 4b9d66cf31598178e56e387d429b390cb91356c4..5b5683f8aedb3e0e57f087de749c5e090823f0c0 100644
--- a/bindings/cmix.go
+++ b/bindings/cmix.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package bindings
 
@@ -35,10 +35,10 @@ type Cmix struct {
 	id  int
 }
 
-// NewCmix creates user storage, generates keys, connects, and registers
-// with the network. Note that this does not register a username/identity, but
-// merely creates a new cryptographic identity for adding such information
-// at a later date.
+// NewCmix creates user storage, generates keys, connects, and registers with
+// the network. Note that this does not register a username/identity, but merely
+// creates a new cryptographic identity for adding such information at a later
+// date.
 //
 // Users of this function should delete the storage directory on error.
 func NewCmix(ndfJSON, storageDir string, password []byte, registrationCode string) error {
@@ -49,8 +49,9 @@ func NewCmix(ndfJSON, storageDir string, password []byte, registrationCode strin
 	return nil
 }
 
-// LoadCmix will load an existing user storage from the storageDir using the password.
-// This will fail if the user storage does not exist or the password is incorrect.
+// LoadCmix will load an existing user storage from the storageDir using the
+// password. This will fail if the user storage does not exist or the password
+// is incorrect.
 //
 // The password is passed as a byte array so that it can be cleared from memory
 // and stored as securely as possible using the MemGuard library.
@@ -59,10 +60,6 @@ func NewCmix(ndfJSON, storageDir string, password []byte, registrationCode strin
 // subprocesses to perform network operations.
 func LoadCmix(storageDir string, password []byte, cmixParamsJSON []byte) (*Cmix,
 	error) {
-	if len(cmixParamsJSON) == 0 {
-		jww.WARN.Printf("cMix params not specified, using defaults...")
-		cmixParamsJSON = GetDefaultCMixParams()
-	}
 
 	params, err := parseCMixParams(cmixParamsJSON)
 	if err != nil {
@@ -82,6 +79,10 @@ func (c *Cmix) GetID() int {
 	return c.id
 }
 
+////////////////////////////////////////////////////////////////////////////////
+// cMix Tracker                                                               //
+////////////////////////////////////////////////////////////////////////////////
+
 // cmixTracker is a singleton used to keep track of extant Cmix objects,
 // preventing race conditions created by passing it over the bindings.
 type cmixTracker struct {
@@ -90,8 +91,8 @@ type cmixTracker struct {
 	mux     sync.RWMutex
 }
 
-// make creates a Cmix from a xxdk.Cmix, assigns it a unique ID,and adds it to
-// the cmixTracker.
+// make creates a Cmix from a [xxdk.Cmix], assigns it a unique ID, and adds it
+// to the cmixTracker.
 func (ct *cmixTracker) make(c *xxdk.Cmix) *Cmix {
 	ct.mux.Lock()
 	defer ct.mux.Unlock()
diff --git a/bindings/connect.go b/bindings/connect.go
index c097d0cb3a23c9366ff6057a690c2b92845bc2aa..df3d4ae46c7f7c0a016ecd75fb576e0e48c98e87 100644
--- a/bindings/connect.go
+++ b/bindings/connect.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package bindings
 
@@ -48,7 +48,7 @@ func (c *Connection) GetId() int {
 // Parameters:
 //  - e2eId - ID of the E2E object in the e2e tracker
 //  - recipientContact - marshalled contact.Contact object
-//  - myIdentity - marshalled ReceptionIdentity object
+//  - e2eParamsJSON - JSON marshalled byte of xxdk.E2EParams object
 func (c *Cmix) Connect(e2eId int, recipientContact, e2eParamsJSON []byte) (
 	*Connection, error) {
 	if len(e2eParamsJSON) == 0 {
@@ -83,9 +83,9 @@ func (c *Cmix) Connect(e2eId int, recipientContact, e2eParamsJSON []byte) (
 //
 // Returns:
 //  - []byte - the JSON marshalled bytes of the E2ESendReport object, which can
-//    be passed into WaitForRoundResult to see if the send succeeded.
+//    be passed into Cmix.WaitForRoundResult to see if the send succeeded.
 func (c *Connection) SendE2E(mt int, payload []byte) ([]byte, error) {
-	rounds, mid, ts, err := c.connection.SendE2E(catalog.MessageType(mt), payload,
+	sendReport, err := c.connection.SendE2E(catalog.MessageType(mt), payload,
 		c.params.Base)
 
 	if err != nil {
@@ -93,9 +93,11 @@ func (c *Connection) SendE2E(mt int, payload []byte) ([]byte, error) {
 	}
 
 	sr := E2ESendReport{
-		RoundsList: makeRoundsList(rounds...),
-		MessageID:  mid.Marshal(),
-		Timestamp:  ts.UnixNano(),
+		RoundsList: makeRoundsList(sendReport.RoundList...),
+		RoundURL:   getRoundURL(sendReport.RoundList[0]),
+		MessageID:  sendReport.MessageId.Marshal(),
+		Timestamp:  sendReport.SentTime.UnixNano(),
+		KeyResidue: sendReport.KeyResidue.Marshal(),
 	}
 
 	return json.Marshal(&sr)
diff --git a/bindings/connect_test.go b/bindings/connect_test.go
index e0f8b38cd106e79c430a5e0b3a56484e87423d7d..5a58b4a715e97983bf9b4d79c560455346da958f 100644
--- a/bindings/connect_test.go
+++ b/bindings/connect_test.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package bindings
 
diff --git a/bindings/delivery.go b/bindings/delivery.go
index 7d549ec7d397da9654ff5be8fccdd7122a6c3c2f..a645e9412dbbc99e49272843241f0dc22058c838 100644
--- a/bindings/delivery.go
+++ b/bindings/delivery.go
@@ -1,14 +1,15 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package bindings
 
 import (
 	"encoding/json"
+	"fmt"
 	"time"
 
 	"github.com/pkg/errors"
@@ -17,15 +18,39 @@ import (
 	"gitlab.com/xx_network/primitives/id"
 )
 
+// dashboardBaseURL is the base of the xx network's round dashboard URL.
+// This should be used by any type of send report's GetRoundURL method.
+var dashboardBaseURL = "https://dashboard.xx.network"
+
+// SetDashboardURL is a function which modifies the base dashboard URL that is
+// returned as part of any send report. Internally, this is defaulted to
+// "https://dashboard.xx.network". This should only be called if the user
+// explicitly wants to modify the dashboard URL. This function is not
+// thread-safe, and as such should only be called on setup.
+//
+// Parameters:
+//  - newURL - A valid URL that will be used for round look up on any send
+//    report.
+func SetDashboardURL(newURL string) {
+	dashboardBaseURL = newURL
+}
+
+// getRoundURL is a helper function which returns the specific round
+// within any type of send report, if they have a round in their RoundsList.
+// This helper function is messenger specific.
+func getRoundURL(round id.Round) string {
+	return fmt.Sprintf("%s/rounds/%d?xxmessenger=true", dashboardBaseURL, round)
+}
+
 // RoundsList contains a list of round IDs.
 //
-// Example marshalled roundList object:
+// JSON Example:
 //  [1001,1003,1006]
 type RoundsList struct {
 	Rounds []uint64
 }
 
-// makeRoundsList converts a list of id.Round into a binding-compatable
+// makeRoundsList converts a list of id.Round into a binding-compatible
 // RoundsList.
 func makeRoundsList(rounds ...id.Round) RoundsList {
 	rl := RoundsList{make([]uint64, len(rounds))}
@@ -70,19 +95,21 @@ type MessageDeliveryCallback interface {
 	EventCallback(delivered, timedOut bool, roundResults []byte)
 }
 
-// WaitForRoundResult allows the caller to get notified if the rounds a
-// message was sent in successfully completed. Under the hood, this uses an API
-// that uses the internal round data, network historical round lookup, and
-// waiting on network events to determine what has (or will) occur.
-//
-// The callbacks will return at timeoutMS if no state update occurs.
+// WaitForRoundResult allows the caller to get notified if the rounds a message
+// was sent in successfully completed. Under the hood, this uses an API that
+// uses the internal round data, network historical round lookup, and waiting on
+// network events to determine what has (or will) occur.
 //
 // This function takes the marshaled send report to ensure a memory leak does
 // not occur as a result of both sides of the bindings holding a reference to
 // the same pointer.
 //
-// roundList is a JSON marshalled RoundsList or any JSON marshalled send report
-// that inherits a RoundsList object.
+// Parameters:
+//  - roundList - JSON marshalled bytes of RoundsList or JSON of any send report
+//    that inherits a [bindings.RoundsList] object
+//  - mdc - callback that adheres to the MessageDeliveryCallback interface
+//  - timeoutMS - timeout when the callback will return if no state update
+//    occurs, in milliseconds
 func (c *Cmix) WaitForRoundResult(
 	roundList []byte, mdc MessageDeliveryCallback, timeoutMS int) error {
 	jww.INFO.Printf("WaitForRoundResult(%s, _, %d)", roundList, timeoutMS)
@@ -113,7 +140,7 @@ func (c *Cmix) WaitForRoundResult(
 
 	timeout := time.Duration(timeoutMS) * time.Millisecond
 
-	err = c.api.GetCmix().GetRoundResults(timeout, f, rl...)
+	c.api.GetCmix().GetRoundResults(timeout, f, rl...)
 
-	return err
+	return nil
 }
diff --git a/bindings/dummy.go b/bindings/dummy.go
new file mode 100644
index 0000000000000000000000000000000000000000..e0915c6cf91022f8556a829787189f6bb0eaaf56
--- /dev/null
+++ b/bindings/dummy.go
@@ -0,0 +1,86 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
+package bindings
+
+import (
+	"gitlab.com/elixxir/client/dummy"
+	"time"
+)
+
+// DummyTraffic is the bindings-layer dummy (or "cover") traffic manager. T
+// The manager can be used to set and get the status of the thread responsible for
+// sending dummy messages.
+type DummyTraffic struct {
+	m *dummy.Manager
+}
+
+// NewDummyTrafficManager creates a DummyTraffic manager and initialises the
+// dummy traffic sending thread. Note that the manager does not start sending
+// dummy traffic until true is passed into DummyTraffic.SetStatus. The time
+// duration between each sending operation and the amount of messages sent each
+// interval are randomly generated values with bounds defined by the given
+// parameters below.
+//
+// Parameters:
+//  - cmixId - a Cmix object ID in the tracker.
+//  - maxNumMessages - the upper bound of the random number of messages sent
+//    each sending cycle.  Suggested value: 5.
+//  - avgSendDeltaMS - the average duration, in milliseconds, to wait between
+//    sends.  Suggested value: 60000.
+//  - randomRangeMS - the upper bound of the interval between sending cycles, in
+//    milliseconds. Sends occur every avgSendDeltaMS +/- a random duration with
+//    an upper bound of randomRangeMS.  Suggested value: 1000.
+func NewDummyTrafficManager(cmixId, maxNumMessages, avgSendDeltaMS,
+	randomRangeMS int) (*DummyTraffic, error) {
+
+	// Get user from singleton
+	net, err := cmixTrackerSingleton.get(cmixId)
+	if err != nil {
+		return nil, err
+	}
+
+	avgSendDelta := time.Duration(avgSendDeltaMS) * time.Millisecond
+	randomRange := time.Duration(randomRangeMS) * time.Millisecond
+
+	m := dummy.NewManager(
+		maxNumMessages, avgSendDelta, randomRange, net.api)
+
+	return &DummyTraffic{m}, net.api.AddService(m.StartDummyTraffic)
+}
+
+// SetStatus sets the state of the DummyTraffic manager's send thread by passing
+// in a boolean parameter. There may be a small delay in between this call and
+// the status of the sending thread to change accordingly. For example, passing
+// false into this call while the sending thread is currently sending messages
+// will not cancel nor halt the sending operation, but will pause the thread
+// once that operation has completed.
+//
+// Parameters:
+//  - status - Input should be true if you want to send dummy messages and false
+//    if you want to pause dummy messages.
+//
+// Returns:
+//  - error - if the DummyTraffic.SetStatus is called too frequently, causing
+//    the internal status channel to fill.
+func (dt *DummyTraffic) SetStatus(status bool) error {
+	return dt.m.SetStatus(status)
+}
+
+// GetStatus returns the current state of the DummyTraffic manager's sending
+// thread. Note that this function does not return the status set by the most
+// recent call to SetStatus. Instead, this call returns the current status of
+// the sending thread. This is due to the small delay that may occur between
+// calling SetStatus and the sending thread taking into effect that status
+// change.
+//
+// Returns:
+//   - bool - Returns true if sending thread is sending dummy messages and false
+//     if sending thread is paused/stopped and is not sending dummy messages.
+func (dt *DummyTraffic) GetStatus() bool {
+	return dt.m.GetStatus()
+}
diff --git a/bindings/e2e.go b/bindings/e2e.go
index 22438e73df9db897e20b785b871d78aadba73307..c072c5cb4e0d6393a27e790d2c6c3b0852d79502 100644
--- a/bindings/e2e.go
+++ b/bindings/e2e.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package bindings
 
@@ -26,20 +26,20 @@ var e2eTrackerSingleton = &e2eTracker{
 	count:   0,
 }
 
-// E2e wraps the xxdk.E2e, implementing additional functions
-// to support the bindings E2e interface.
+// E2e wraps the xxdk.E2e, implementing additional functions to support the
+// bindings E2e interface.
 type E2e struct {
 	api *xxdk.E2e
 	id  int
 }
 
-// GetID returns the e2eTracker ID for the E2e object.
+// GetID returns the ID for this E2e in the e2eTracker.
 func (e *E2e) GetID() int {
 	return e.id
 }
 
 // Login creates and returns a new E2e object and adds it to the
-// e2eTrackerSingleton. identity should be created via
+// e2eTrackerSingleton. Identity should be created via
 // Cmix.MakeReceptionIdentity and passed in here. If callbacks is left nil, a
 // default auth.Callbacks will be used.
 func Login(cmixId int, callbacks AuthCallbacks, identity,
@@ -80,7 +80,7 @@ func Login(cmixId int, callbacks AuthCallbacks, identity,
 }
 
 // LoginEphemeral creates and returns a new ephemeral E2e object and adds it to
-// the e2eTrackerSingleton. identity should be created via
+// the e2eTrackerSingleton. Identity should be created via
 // Cmix.MakeReceptionIdentity or Cmix.MakeLegacyReceptionIdentity and passed in
 // here. If callbacks is left nil, a default auth.Callbacks will be used.
 func LoginEphemeral(cmixId int, callbacks AuthCallbacks, identity,
@@ -126,13 +126,15 @@ func (e *E2e) GetContact() []byte {
 	return e.api.GetReceptionIdentity().GetContact().Marshal()
 }
 
-// GetUdAddressFromNdf retrieve the User Discovery's network address fom the NDF.
+// GetUdAddressFromNdf retrieve the User Discovery's network address fom the
+// NDF.
 func (e *E2e) GetUdAddressFromNdf() string {
 	return e.api.GetCmix().GetInstance().GetPartialNdf().
 		Get().UDB.Address
 }
 
-// GetUdCertFromNdf retrieves the User Discovery's TLS certificate from the NDF.
+// GetUdCertFromNdf retrieves the User Discovery's TLS certificate (in PEM
+// format) from the NDF.
 func (e *E2e) GetUdCertFromNdf() []byte {
 	return []byte(e.api.GetCmix().GetInstance().GetPartialNdf().Get().UDB.Cert)
 }
@@ -143,19 +145,26 @@ func (e *E2e) GetUdCertFromNdf() []byte {
 // Returns
 //  - []byte - A byte marshalled contact.Contact.
 func (e *E2e) GetUdContactFromNdf() ([]byte, error) {
-	udIdData := e.api.GetCmix().GetInstance().GetPartialNdf().Get().UDB.ID
+	// Retrieve data from E2e
+	netDef := e.api.GetCmix().GetInstance().GetPartialNdf().Get()
+	e2eGroup := e.api.GetE2E().GetGroup()
+
+	// Unmarshal UD ID
+	udIdData := netDef.UDB.ID
 	udId, err := id.Unmarshal(udIdData)
 	if err != nil {
 		return nil, err
 	}
 
-	udDhPubKeyData := e.api.GetCmix().GetInstance().GetPartialNdf().Get().UDB.DhPubKey
-	udDhPubKey := e.api.GetE2E().GetGroup().NewInt(1)
+	// Unmarshal DH pub key
+	udDhPubKeyData := netDef.UDB.DhPubKey
+	udDhPubKey := e2eGroup.NewInt(1)
 	err = udDhPubKey.UnmarshalJSON(udDhPubKeyData)
 	if err != nil {
 		return nil, err
 	}
 
+	// Construct contact
 	udContact := contact.Contact{
 		ID:       udId,
 		DhPubKey: udDhPubKey,
@@ -178,11 +187,11 @@ type authCallback struct {
 }
 
 // convertAuthCallbacks turns an auth.Callbacks into an AuthCallbacks.
-func convertAuthCallbacks(requestor contact.Contact,
+func convertAuthCallbacks(requester contact.Contact,
 	receptionID receptionID.EphemeralIdentity, round rounds.Round) (
 	contact []byte, receptionId []byte, ephemeralId int64, roundId int64) {
 
-	contact = requestor.Marshal()
+	contact = requester.Marshal()
 	receptionId = receptionID.Source.Marshal()
 	ephemeralId = int64(receptionID.EphId.UInt64())
 	roundId = int64(round.ID)
@@ -207,6 +216,10 @@ func (a *authCallback) Reset(partner contact.Contact,
 	a.bindingsCbs.Reset(convertAuthCallbacks(partner, receptionID, round))
 }
 
+////////////////////////////////////////////////////////////////////////////////
+// E2E Tracker                                                                //
+////////////////////////////////////////////////////////////////////////////////
+
 // e2eTracker is a singleton used to keep track of extant E2e objects,
 // preventing race conditions created by passing it over the bindings.
 type e2eTracker struct {
@@ -222,15 +235,15 @@ func (ct *e2eTracker) make(c *xxdk.E2e) *E2e {
 	ct.mux.Lock()
 	defer ct.mux.Unlock()
 
-	id := ct.count
+	e2eID := ct.count
 	ct.count++
 
-	ct.tracked[id] = &E2e{
+	ct.tracked[e2eID] = &E2e{
 		api: c,
-		id:  id,
+		id:  e2eID,
 	}
 
-	return ct.tracked[id]
+	return ct.tracked[e2eID]
 }
 
 // get an E2e from the e2eTracker given its ID.
diff --git a/bindings/e2eAuth.go b/bindings/e2eAuth.go
index b2277eb3e3c77ae54ab933dae3b23c9edee9ef25..f7c01b53650eb210398cf6be27289a8ef3f6de18 100644
--- a/bindings/e2eAuth.go
+++ b/bindings/e2eAuth.go
@@ -1,8 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package bindings
@@ -35,12 +35,12 @@ import (
 //
 // Parameters:
 //  - partnerContact - the marshalled bytes of the contact.Contact object.
-//  - myFacts - stringified list of fact.FactList.
+//  - factsListJson - the JSON marshalled bytes of [fact.FactList].
 //
 // Returns:
 //  - int64 - ID of the round (convert to uint64)
 func (e *E2e) Request(partnerContact, factsListJson []byte) (int64, error) {
-	var factsList []Fact
+	var factsList fact.FactList
 	err := json.Unmarshal(factsListJson, &factsList)
 	if err != nil {
 		return 0, err
@@ -51,15 +51,7 @@ func (e *E2e) Request(partnerContact, factsListJson []byte) (int64, error) {
 		return 0, err
 	}
 
-	myFacts := fact.FactList{}
-	for _, f := range factsList {
-		myFacts = append(myFacts, fact.Fact{
-			Fact: f.Fact,
-			T:    fact.FactType(f.Type),
-		})
-	}
-
-	roundID, err := e.api.GetAuth().Request(partner, myFacts)
+	roundID, err := e.api.GetAuth().Request(partner, factsList)
 
 	return int64(roundID), err
 }
@@ -179,8 +171,7 @@ func (e *E2e) DeleteSentRequests() error {
 	return e.api.GetAuth().DeleteSentRequests()
 }
 
-// DeleteReceiveRequests clears all received requests from auth
-// storage.
+// DeleteReceiveRequests clears all received requests from auth storage.
 func (e *E2e) DeleteReceiveRequests() error {
 	return e.api.GetAuth().DeleteReceiveRequests()
 }
diff --git a/bindings/e2eHandler.go b/bindings/e2eHandler.go
index 83ca76d62341b62162fa97d19be63b5537c517d2..4b63407520f8e1aa756f2e749e4b0971fc72fdd2 100644
--- a/bindings/e2eHandler.go
+++ b/bindings/e2eHandler.go
@@ -1,21 +1,21 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package bindings
 
 import (
 	"encoding/json"
 	"fmt"
+
 	"github.com/pkg/errors"
 	jww "github.com/spf13/jwalterweatherman"
 	"gitlab.com/elixxir/client/catalog"
 	"gitlab.com/elixxir/client/cmix/identity/receptionID"
 	"gitlab.com/elixxir/client/cmix/rounds"
-	"gitlab.com/elixxir/client/e2e"
 	"gitlab.com/elixxir/primitives/format"
 	"gitlab.com/xx_network/primitives/id"
 )
@@ -23,14 +23,20 @@ import (
 // E2ESendReport is the bindings' representation of the return values of
 // SendE2E.
 //
-// Example E2ESendReport:
-//  {"Rounds":[1,5,9],
-//   "MessageID":"51Yy47uZbP0o2Y9B/kkreDLTB6opUol3M3mYiY2dcdQ=",
-//   "Timestamp":1653582683183384000}
+// E2ESendReport Example JSON:
+//  {
+//		"Rounds": [ 1, 4, 9],
+//      "RoundURL":"https://dashboard.xx.network/rounds/25?xxmessenger=true",
+//		"MessageID": "iM34yCIr4Je8ZIzL9iAAG1UWAeDiHybxMTioMAaezvs=",
+//		"Timestamp": 1661532254302612000,
+//		"KeyResidue": "9q2/A69EAuFM1hFAT7Bzy5uGOQ4T6bPFF72h5PlgCWE="
+//  }
 type E2ESendReport struct {
 	RoundsList
-	MessageID []byte
-	Timestamp int64
+	RoundURL   string
+	MessageID  []byte
+	Timestamp  int64
+	KeyResidue []byte
 }
 
 // GetReceptionID returns the marshalled default IDs.
@@ -41,6 +47,19 @@ func (e *E2e) GetReceptionID() []byte {
 	return e.api.GetE2E().GetReceptionID().Marshal()
 }
 
+// DeleteContact removes a partner from E2e's storage.
+//
+// Parameters:
+//  - partnerID - the marshalled bytes of id.ID.
+func (e *E2e) DeleteContact(partnerID []byte) error {
+	partner, err := id.Unmarshal(partnerID)
+	if err != nil {
+		return err
+	}
+
+	return e.api.DeleteContact(partner)
+}
+
 // GetAllPartnerIDs returns a list of all partner IDs that the user has an E2E
 // relationship with.
 //
@@ -117,30 +136,36 @@ func (e *E2e) RemoveService(tag string) error {
 //
 // Returns:
 //  - []byte - the JSON marshalled bytes of the E2ESendReport object, which can
-//    be passed into WaitForRoundResult to see if the send succeeded.
+//    be passed into Cmix.WaitForRoundResult to see if the send succeeded.
 func (e *E2e) SendE2E(messageType int, recipientId, payload,
-	e2eParams []byte) ([]byte, error) {
-	// Note that specifically these are the Base params from xxdk.E2EParams
-	params := e2e.GetDefaultParams()
-	err := params.UnmarshalJSON(e2eParams)
+	e2eParamsJSON []byte) ([]byte, error) {
+	if len(e2eParamsJSON) == 0 {
+		jww.WARN.Printf("e2e params not specified, using defaults...")
+		e2eParamsJSON = GetDefaultE2EParams()
+	}
+	params, err := parseE2EParams(e2eParamsJSON)
 	if err != nil {
 		return nil, err
 	}
+
 	recipient, err := id.Unmarshal(recipientId)
 	if err != nil {
 		return nil, err
 	}
 
-	roundIds, messageId, ts, err := e.api.GetE2E().SendE2E(
-		catalog.MessageType(messageType), recipient, payload, params)
+	sendReport, err := e.api.GetE2E().SendE2E(
+		catalog.MessageType(messageType), recipient, payload,
+		params.Base)
 	if err != nil {
 		return nil, err
 	}
 
 	result := E2ESendReport{
-		RoundsList: makeRoundsList(roundIds...),
-		MessageID:  messageId.Marshal(),
-		Timestamp:  ts.UnixNano(),
+		RoundsList: makeRoundsList(sendReport.RoundList...),
+		RoundURL:   getRoundURL(sendReport.RoundList[0]),
+		MessageID:  sendReport.MessageId.Marshal(),
+		Timestamp:  sendReport.SentTime.UnixNano(),
+		KeyResidue: sendReport.KeyResidue.Marshal(),
 	}
 	return json.Marshal(result)
 }
@@ -166,11 +191,9 @@ func (e *E2e) AddService(tag string, processor Processor) error {
 //  - messageType - message type from the sender you want to listen for.
 //  - newListener: A provider for a callback to hear a message.
 //    Do not pass nil to this.
-func (e *E2e) RegisterListener(senderID []byte,
-	messageType int,
-	newListener Listener) error {
-	jww.INFO.Printf("RegisterListener(%v, %d)", senderID,
-		messageType)
+func (e *E2e) RegisterListener(
+	senderID []byte, messageType int, newListener Listener) error {
+	jww.INFO.Printf("RegisterListener(%v, %d)", senderID, messageType)
 
 	// Convert senderID to id.Id object
 	var uid *id.ID
diff --git a/bindings/errors.go b/bindings/errors.go
index 32c945c80c219626623b39ce12e3f299c1f73cef..4c15d28df9ae1fd4c6a748b3ed1b23bb317c7b4c 100644
--- a/bindings/errors.go
+++ b/bindings/errors.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package bindings
 
@@ -46,14 +46,14 @@ const (
 	UnrecognizedMessage = UnrecognizedCode + "Unrecognized error from XX backend, please report"
 )
 
-// CreateUserFriendlyErrorMessage will convert the passed in error string
-// to an error string that is user-friendly if a substring match is
-// found to a common error. Common errors is a map which can be updated
-// using UpdateCommonErrors. If the error is not common, some simple parsing
-// is done on the error message to make it more user-accessible, removing
-// backend specific jargon.
+// CreateUserFriendlyErrorMessage will convert the passed in error string to an
+// error string that is user-friendly if a substring match is found to a
+// common error. Common errors is a map that can be updated using
+// UpdateCommonErrors. If the error is not common, some simple parsing is done
+// on the error message to make it more user-accessible, removing backend
+// specific jargon.
 //
-// Parameters
+// Parameters:
 //   - errStr - an error returned from the backend.
 //
 // Returns
@@ -97,16 +97,18 @@ func CreateUserFriendlyErrorMessage(errStr string) string {
 	return fmt.Sprintf("%s: %v", UnrecognizedCode, errStr)
 }
 
-// UpdateCommonErrors updates the internal error mapping DB. This internal database
-// maps errors returned from the backend to user-friendly error messages.
+// UpdateCommonErrors updates the internal error mapping database. This internal
+// database maps errors returned from the backend to user-friendly error
+// messages.
 //
-// Parameters
+// Parameters:
 //  - jsonFile - contents of a JSON file whose format conforms to the example below.
+//
 // Example Input:
-//   {
-//  	"Failed to Unmarshal Conversation": "Could not retrieve conversation",
-//  	"Failed to unmarshal SentRequestMap": "Failed to pull up friend requests",
-//  	"cannot create username when network is not health": "Cannot create username, unable to connect to network",
+//  {
+//    "Failed to Unmarshal Conversation": "Could not retrieve conversation",
+//    "Failed to unmarshal SentRequestMap": "Failed to pull up friend requests",
+//    "cannot create username when network is not health": "Cannot create username, unable to connect to network",
 //  }
 func UpdateCommonErrors(jsonFile string) error {
 	errorMux.Lock()
diff --git a/bindings/errors_test.go b/bindings/errors_test.go
index 0dbcf0220e1232aa450d0884363e4c461fe42c66..fdb6539d0489e753196cfb89f50b29e0dffa45c0 100644
--- a/bindings/errors_test.go
+++ b/bindings/errors_test.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package bindings
 
diff --git a/bindings/fileTransfer.go b/bindings/fileTransfer.go
index b0182ed6e2cb9c018a54ee716946e60cbb74f328..2a25aa4a7829c0fdd576c9c660709261dd23997c 100644
--- a/bindings/fileTransfer.go
+++ b/bindings/fileTransfer.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package bindings
 
@@ -32,12 +32,12 @@ type FileTransfer struct {
 //
 // Example JSON:
 //  {
-//   "TransferID":"B4Z9cwU18beRoGbk5xBjbcd5Ryi9ZUFA2UBvi8FOHWo=",
-//   "SenderID":"emV6aW1hAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD",
-//   "Preview":"aXQncyBtZSBhIHByZXZpZXc=",
-//   "Name":"testfile.txt",
-//   "Type":"text file",
-//   "Size":2048
+//    "TransferID":"B4Z9cwU18beRoGbk5xBjbcd5Ryi9ZUFA2UBvi8FOHWo=",
+//    "SenderID":"emV6aW1hAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD",
+//    "Preview":"aXQncyBtZSBhIHByZXZpZXc=",
+//    "Name":"testfile.txt",
+//    "Type":"text file",
+//    "Size":2048
 //  }
 type ReceivedFile struct {
 	TransferID []byte // ID of the file transfer
@@ -51,10 +51,10 @@ type ReceivedFile struct {
 // FileSend is a public struct that contains the file contents and its name,
 // type, and preview.
 //  {
-//   "Name":"testfile.txt",
-//   "Type":"text file",
-//   "Preview":"aXQncyBtZSBhIHByZXZpZXc=",
-//   "Contents":"VGhpcyBpcyB0aGUgZnVsbCBjb250ZW50cyBvZiB0aGUgZmlsZSBpbiBieXRlcw=="
+//    "Name":"testfile.txt",
+//    "Type":"text file",
+//    "Preview":"aXQncyBtZSBhIHByZXZpZXc=",
+//    "Contents":"VGhpcyBpcyB0aGUgZnVsbCBjb250ZW50cyBvZiB0aGUgZmlsZSBpbiBieXRlcw=="
 //  }
 type FileSend struct {
 	Name     string // Name of the file
@@ -68,10 +68,10 @@ type FileSend struct {
 //
 // Example JSON:
 //  {
-//   "Completed":false,
-//   "Transmitted":128,
-//   "Total":2048,
-//   "Err":null
+//    "Completed":false,
+//    "Transmitted":128,
+//    "Total":2048,
+//    "Err":null
 //  }
 type Progress struct {
 	Completed   bool  // Status of transfer (true if done)
@@ -179,23 +179,23 @@ func InitFileTransfer(e2eID int, receiveFileCallback ReceiveFileCallback,
 // Parameters:
 //  - payload - JSON marshalled FileSend
 //  - recipientID - marshalled recipient id.ID
-//  - paramsJSON - JSON marshalled e2e.Params
 //  - retry - number of retries allowed
 //  - callback - callback that reports file sending progress
-//  - period - duration to wait between progress callbacks triggering
+//  - period - Duration (in ms) to wait between progress callbacks triggering.
+//    This value should depend on how frequently you want to receive updates,
+//    and should be tuned to your implementation.
 //
 // Returns:
 //  - []byte - unique file transfer ID
 func (f *FileTransfer) Send(payload, recipientID []byte, retry float32,
-	callback FileTransferSentProgressCallback, period string) ([]byte, error) {
+	callback FileTransferSentProgressCallback, period int) ([]byte, error) {
 	// Unmarshal recipient ID
 	recipient, err := id.Unmarshal(recipientID)
 	if err != nil {
 		return nil, err
 	}
 
-	// Parse duration to time.Duration
-	p, err := time.ParseDuration(period)
+	p := time.Millisecond * time.Duration(period)
 
 	// Wrap transfer progress callback to be passed to fileTransfer layer
 	cb := func(completed bool, arrived, total uint16,
@@ -269,9 +269,11 @@ func (f *FileTransfer) CloseSend(tidBytes []byte) error {
 // Parameters:
 //  - tidBytes - file transfer ID
 //  - callback - callback that reports file reception progress
-//  - period - duration to wait between progress callbacks triggering
+//  - period - Duration (in ms) to wait between progress callbacks triggering.
+//    This value should depend on how frequently you want to receive updates,
+//    and should be tuned to your implementation.
 func (f *FileTransfer) RegisterSentProgressCallback(tidBytes []byte,
-	callback FileTransferSentProgressCallback, period string) error {
+	callback FileTransferSentProgressCallback, period int) error {
 	cb := func(completed bool, arrived, total uint16,
 		st fileTransfer.SentTransfer, t fileTransfer.FilePartTracker, err error) {
 		prog := &Progress{
@@ -283,10 +285,7 @@ func (f *FileTransfer) RegisterSentProgressCallback(tidBytes []byte,
 		pm, err := json.Marshal(prog)
 		callback.Callback(pm, &FilePartTracker{t}, err)
 	}
-	p, err := time.ParseDuration(period)
-	if err != nil {
-		return err
-	}
+	p := time.Millisecond * time.Duration(period)
 	tid := ftCrypto.UnmarshalTransferID(tidBytes)
 
 	return f.w.RegisterSentProgressCallback(&tid, cb, p)
@@ -300,9 +299,11 @@ func (f *FileTransfer) RegisterSentProgressCallback(tidBytes []byte,
 // Parameters:
 //  - tidBytes - file transfer ID
 //  - callback - callback that reports file reception progress
-//  - period - duration to wait between progress callbacks triggering
+//  - period - Duration (in ms) to wait between progress callbacks triggering.
+//    This value should depend on how frequently you want to receive updates,
+//    and should be tuned to your implementation.
 func (f *FileTransfer) RegisterReceivedProgressCallback(tidBytes []byte,
-	callback FileTransferReceiveProgressCallback, period string) error {
+	callback FileTransferReceiveProgressCallback, period int) error {
 	cb := func(completed bool, received, total uint16,
 		rt fileTransfer.ReceivedTransfer, t fileTransfer.FilePartTracker, err error) {
 		prog := &Progress{
@@ -314,10 +315,8 @@ func (f *FileTransfer) RegisterReceivedProgressCallback(tidBytes []byte,
 		pm, err := json.Marshal(prog)
 		callback.Callback(pm, &FilePartTracker{t}, err)
 	}
-	p, err := time.ParseDuration(period)
-	if err != nil {
-		return err
-	}
+	p := time.Millisecond * time.Duration(period)
+
 	tid := ftCrypto.UnmarshalTransferID(tidBytes)
 	return f.w.RegisterReceivedProgressCallback(&tid, cb, p)
 }
diff --git a/bindings/fileTransfer_test.go b/bindings/fileTransfer_test.go
index 10d49d9b81cbea043d281de9f4377508a6e2063f..81a0679e0a9737e4db9465e23d8d3519d70b9b9b 100644
--- a/bindings/fileTransfer_test.go
+++ b/bindings/fileTransfer_test.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package bindings
 
diff --git a/bindings/follow.go b/bindings/follow.go
index 482bbd9cd83ab254ee2677a494d8e720df67c88d..503aa5e1a5301ab1cd0124044e7a57a87fe28eea 100644
--- a/bindings/follow.go
+++ b/bindings/follow.go
@@ -1,15 +1,16 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package bindings
 
 import (
 	"encoding/json"
 	"fmt"
+	"gitlab.com/elixxir/client/cmix/message"
 	"time"
 
 	"github.com/pkg/errors"
@@ -26,29 +27,28 @@ import (
 // they are stopped if there is no internet access.
 //
 // Threads Started:
-//   - Network Follower (/network/follow.go)
-//   	tracks the network events and hands them off to workers for handling.
-//   - Historical Round Retrieval (/network/rounds/historical.go)
-// 		retrieves data about rounds that are too old to be stored by the client.
-//	 - Message Retrieval Worker Group (/network/rounds/retrieve.go)
-//		requests all messages in a given round from the gateway of the last
-//		nodes.
-//	 - Message Handling Worker Group (/network/message/handle.go)
-//		decrypts and partitions messages when signals via the Switchboard.
-//	 - Health Tracker (/network/health),
-//		via the network instance, tracks the state of the network.
-//	 - Garbled Messages (/network/message/garbled.go)
-//		can be signaled to check all recent messages that could be decoded. It
-//		uses a message store on disk for persistence.
-//	 - Critical Messages (/network/message/critical.go)
-//		ensures all protocol layer mandatory messages are sent. It uses a
-//		message store on disk for persistence.
-//	 - KeyExchange Trigger (/keyExchange/trigger.go)
-//		responds to sent rekeys and executes them.
-//   - KeyExchange Confirm (/keyExchange/confirm.go)
-//		responds to confirmations of successful rekey operations.
-//   - Auth Callback (/auth/callback.go)
-//      handles both auth confirm and requests.
+//  - Network Follower (/network/follow.go)
+//    tracks the network events and hands them off to workers for handling.
+//  - Historical Round Retrieval (/network/rounds/historical.go)
+//    retrieves data about rounds that are too old to be stored by the client.
+//  - Message Retrieval Worker Group (/network/rounds/retrieve.go)
+//	  requests all messages in a given round from the gateway of the last nodes.
+//  - Message Handling Worker Group (/network/message/handle.go)
+//	  decrypts and partitions messages when signals via the Switchboard.
+//	- Health Tracker (/network/health),
+//	  via the network instance, tracks the state of the network.
+//  - Garbled Messages (/network/message/garbled.go)
+//	  can be signaled to check all recent messages that could be decoded. It
+//	  uses a message store on disk for persistence.
+//	- Critical Messages (/network/message/critical.go)
+//	  ensures all protocol layer mandatory messages are sent. It uses a message
+//	  store on disk for persistence.
+//	- KeyExchange Trigger (/keyExchange/trigger.go)
+//	  responds to sent rekeys and executes them.
+//  - KeyExchange Confirm (/keyExchange/confirm.go)
+//	  responds to confirmations of successful rekey operations.
+//  - Auth Callback (/auth/callback.go)
+//    handles both auth confirm and requests.
 func (c *Cmix) StartNetworkFollower(timeoutMS int) error {
 	timeout := time.Duration(timeoutMS) * time.Millisecond
 	return c.api.StartNetworkFollower(timeout)
@@ -58,7 +58,7 @@ func (c *Cmix) StartNetworkFollower(timeoutMS int) error {
 // an error if the follower is in the wrong state to stop or if it fails to stop
 // it.
 //
-// if the network follower is running and this fails, the Cmix object will
+// If the network follower is running and this fails, the Cmix object will
 // most likely be in an unrecoverable state and need to be trashed.
 func (c *Cmix) StopNetworkFollower() error {
 	if err := c.api.StopNetworkFollower(); err != nil {
@@ -84,11 +84,9 @@ func (c *Cmix) WaitForNetwork(timeoutMS int) bool {
 
 // NetworkFollowerStatus gets the state of the network follower. It returns a
 // status with the following values:
-//
-// Status:
-//  - Stopped  - 0
-//  - Running  - 2000
-//  - Stopping - 3000
+//  Stopped  - 0
+//  Running  - 2000
+//  Stopping - 3000
 func (c *Cmix) NetworkFollowerStatus() int {
 	return int(c.api.NetworkFollowerStatus())
 }
@@ -103,10 +101,11 @@ type NodeRegistrationReport struct {
 // GetNodeRegistrationStatus returns the current state of node registration.
 //
 // Returns:
-//  - []bye - A marshalled NodeRegistrationReport containing the number of
-//    nodes the user is registered with and the number of nodes present in the NDF.
-//  - An error if it cannot get the node registration status. The most likely cause
-//    is that the network is unhealthy.
+//  - []byte - A marshalled NodeRegistrationReport containing the number of
+//    nodes the user is registered with and the number of nodes present in the
+//    NDF.
+//  - An error if it cannot get the node registration status. The most likely
+//    cause is that the network is unhealthy.
 func (c *Cmix) GetNodeRegistrationStatus() ([]byte, error) {
 	numNodesRegistered, numNodes, err := c.api.GetNodeRegistrationStatus()
 	if err != nil {
@@ -137,6 +136,22 @@ func (c *Cmix) IsHealthy() bool {
 	return c.api.GetCmix().IsHealthy()
 }
 
+// GetRunningProcesses returns the names of all running processes at the time
+// of this call. Note that this list may change and is subject to race
+// conditions if multiple threads are in the process of starting or stopping.
+//
+// Returns:
+//  - []byte - A JSON marshalled list of all running processes.
+//
+// JSON Example:
+//  {
+//    "FileTransfer{BatchBuilderThread, FilePartSendingThread#0, FilePartSendingThread#1, FilePartSendingThread#2, FilePartSendingThread#3}",
+//    "MessageReception Worker 0"
+//  }
+func (c *Cmix) GetRunningProcesses() ([]byte, error) {
+	return json.Marshal(c.api.GetRunningProcesses())
+}
+
 // NetworkHealthCallback contains a callback that is used to receive
 // notification if network health changes.
 type NetworkHealthCallback interface {
@@ -169,3 +184,54 @@ func (c *Cmix) RegisterClientErrorCallback(clientError ClientError) {
 		}
 	}()
 }
+
+// TrackServicesCallback is the callback for [Cmix.TrackServices].
+// This will pass to the user a JSON-marshalled list of backend services.
+// If there was an error retrieving or marshalling the service list,
+// there is an error for the second parameter which will be non-null.
+//
+// Parameters:
+//  - marshalData - JSON marshalled bytes of [message.ServiceList], which is an
+//    array of [id.ID] and [message.Service].
+//  - err - JSON unmarshalling error
+//
+// Example JSON:
+//  [
+//    {
+//      "Id": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD", // bytes of id.ID encoded as base64 string
+//      "Services": [
+//        {
+//          "Identifier": "AQID",                             // bytes encoded as base64 string
+//          "Tag": "TestTag 1",                               // string
+//          "Metadata": "BAUG"                                // bytes encoded as base64 string
+//        }
+//      ]
+//    },
+//    {
+//      "Id": "AAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD",
+//      "Services": [
+//        {
+//          "Identifier": "AQID",
+//          "Tag": "TestTag 2",
+//          "Metadata": "BAUG"
+//        }
+//      ]
+//    },
+//  ]
+type TrackServicesCallback interface {
+	Callback(marshalData []byte, err error)
+}
+
+// TrackServices will return via a callback the list of services the
+// backend keeps track of, which is formally referred to as a
+// [message.ServiceList]. This may be passed into other bindings call which
+// may need context on the available services for this client.
+//
+// Parameters:
+//  - cb - A TrackServicesCallback, which will be passed the marshalled
+//    message.ServiceList.
+func (c *Cmix) TrackServices(cb TrackServicesCallback) {
+	c.api.GetCmix().TrackServices(func(list message.ServiceList) {
+		cb.Callback(json.Marshal(list))
+	})
+}
diff --git a/bindings/group.go b/bindings/group.go
index 00951c269e43843fd3bd05609f1bddc9562cb844..ddb6f12b985ebfaf7e6d7c1df0c2c3b86cae3c45 100644
--- a/bindings/group.go
+++ b/bindings/group.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package bindings
 
@@ -17,68 +17,9 @@ import (
 	gs "gitlab.com/elixxir/client/groupChat/groupStore"
 	"gitlab.com/elixxir/primitives/format"
 	"gitlab.com/xx_network/primitives/id"
-	"sync"
 	"time"
 )
 
-////////////////////////////////////////////////////////////////////////////////
-// Group Singleton Tracker                                               //
-////////////////////////////////////////////////////////////////////////////////
-
-// groupTrackerSingleton is used to track Group objects so that they can be
-// referenced by ID back over the bindings.
-var groupTrackerSingleton = &groupTracker{
-	tracked: make(map[int]*Group),
-	count:   0,
-}
-
-// groupTracker is a singleton used to keep track of extant Group objects,
-// preventing race conditions created by passing it over the bindings.
-type groupTracker struct {
-	tracked map[int]*Group
-	count   int
-	mux     sync.RWMutex
-}
-
-// make create a Group from a groupStore.Group, assigns it a unique ID, and
-// adds it to the groupChatTracker.
-func (ut *groupTracker) make(g gs.Group) *Group {
-	ut.mux.Lock()
-	defer ut.mux.Unlock()
-
-	id := ut.count
-	ut.count++
-
-	ut.tracked[id] = &Group{
-		g:  g,
-		id: id,
-	}
-
-	return ut.tracked[id]
-}
-
-// get a Group from the groupChatTracker given its ID.
-func (ut *groupTracker) get(id int) (*Group, error) {
-	ut.mux.RLock()
-	defer ut.mux.RUnlock()
-
-	g, exist := ut.tracked[id]
-	if !exist {
-		return nil, errors.Errorf(
-			"Cannot get Group for ID %d, does not exist", id)
-	}
-
-	return g, nil
-}
-
-// delete removes a Group from the groupTracker.
-func (ut *groupTracker) delete(id int) {
-	ut.mux.Lock()
-	defer ut.mux.Unlock()
-
-	delete(ut.tracked, id)
-}
-
 ////////////////////////////////////////////////////////////////////////////////
 // Group Chat                                                                 //
 ////////////////////////////////////////////////////////////////////////////////
@@ -105,8 +46,7 @@ func NewGroupChat(e2eID int,
 
 	// Construct a wrapper for the request callback
 	requestCb := func(g gs.Group) {
-		newGroup := groupTrackerSingleton.make(g)
-		requestFunc.Callback(newGroup)
+		requestFunc.Callback(&Group{g: g})
 	}
 
 	// Construct a group chat manager
@@ -129,16 +69,16 @@ func NewGroupChat(e2eID int,
 //    IDs of members the user wants to add to the group.
 //  - message - the initial message sent to all members in the group. This is an
 //    optional parameter and may be nil.
-//  - tag - the name of the group decided by the creator. This is an optional
+//  - name - the name of the group decided by the creator. This is an optional
 //    parameter and may be nil. If nil the group will be assigned the default
 //    name.
 //
 // Returns:
 //  - []byte - the JSON marshalled bytes of the GroupReport object, which can be
-//    passed into WaitForRoundResult to see if the group request message send
-//    succeeded.
-func (g *GroupChat) MakeGroup(membershipBytes []byte, message, name []byte) (
-	[]byte, error) {
+//    passed into Cmix.WaitForRoundResult to see if the group request message
+//    send succeeded.
+func (g *GroupChat) MakeGroup(
+	membershipBytes, message, name []byte) ([]byte, error) {
 
 	// Unmarshal membership list into a list of []*id.Id
 	var members []*id.ID
@@ -148,7 +88,7 @@ func (g *GroupChat) MakeGroup(membershipBytes []byte, message, name []byte) (
 	}
 
 	// Construct group
-	grp, rounds, status, err := g.m.MakeGroup(members, name, message)
+	grp, roundIDs, status, err := g.m.MakeGroup(members, name, message)
 	if err != nil {
 		return nil, err
 	}
@@ -156,7 +96,8 @@ func (g *GroupChat) MakeGroup(membershipBytes []byte, message, name []byte) (
 	// Construct the group report
 	report := GroupReport{
 		Id:         grp.ID.Bytes(),
-		RoundsList: makeRoundsList(rounds...),
+		RoundsList: makeRoundsList(roundIDs...),
+		RoundURL:   getRoundURL(roundIDs[0]),
 		Status:     int(status),
 	}
 
@@ -199,6 +140,7 @@ func (g *GroupChat) ResendRequest(groupId []byte) ([]byte, error) {
 	report := &GroupReport{
 		Id:         grp.ID.Bytes(),
 		RoundsList: makeRoundsList(rnds...),
+		RoundURL:   getRoundURL(rnds[0]),
 		Status:     int(status),
 	}
 
@@ -211,22 +153,14 @@ func (g *GroupChat) ResendRequest(groupId []byte) ([]byte, error) {
 // with the same trackedGroupId.
 //
 // Parameters:
-//  - trackedGroupId - the ID to retrieve the Group object within the backend's
-//    tracking system. This is received by GroupRequest.Callback.
-func (g *GroupChat) JoinGroup(trackedGroupId int) error {
-	// Retrieve group from singleton
-	grp, err := groupTrackerSingleton.get(trackedGroupId)
+//  - serializedGroupData - the result of calling Group.Serialize() on
+//    any Group object returned over the bindings
+func (g *GroupChat) JoinGroup(serializedGroupData []byte) error {
+	grp, err := DeserializeGroup(serializedGroupData)
 	if err != nil {
 		return err
 	}
-
-	// Join group
-	err = g.m.JoinGroup(grp.g)
-	if err != nil {
-		return err
-	}
-
-	return nil
+	return g.m.JoinGroup(grp.g)
 }
 
 // LeaveGroup deletes a group so a user no longer has access.
@@ -246,17 +180,16 @@ func (g *GroupChat) LeaveGroup(groupId []byte) error {
 // Send is the bindings-level function for sending to a group.
 //
 // Parameters:
-//  - groupId - the byte data representing a group ID.
-//    This can be pulled from a marshalled GroupReport.
+//  - groupId - the byte data representing a group ID. This can be pulled from
+//    marshalled GroupReport.
 //  - message - the message that the user wishes to send to the group.
 //  - tag - the tag associated with the message. This tag may be empty.
 //
 // Returns:
 //  - []byte - the JSON marshalled bytes of the GroupSendReport object, which
-//    can be passed into WaitForRoundResult to see if the group message send
-//    succeeded.
-func (g *GroupChat) Send(groupId,
-	message []byte, tag string) ([]byte, error) {
+//    can be passed into Cmix.WaitForRoundResult to see if the group message
+//    send succeeded.
+func (g *GroupChat) Send(groupId, message []byte, tag string) ([]byte, error) {
 	groupID, err := id.Unmarshal(groupId)
 	if err != nil {
 		return nil, errors.Errorf("Failed to unmarshal group ID: %+v", err)
@@ -270,7 +203,8 @@ func (g *GroupChat) Send(groupId,
 
 	// Construct send report
 	sendReport := &GroupSendReport{
-		RoundsList: makeRoundsList(round),
+		RoundURL:   getRoundURL(round.ID),
+		RoundsList: makeRoundsList(round.ID),
 		Timestamp:  timestamp.UnixNano(),
 		MessageID:  msgID.Bytes(),
 	}
@@ -291,7 +225,7 @@ func (g *GroupChat) GetGroups() ([]byte, error) {
 //
 // Parameters:
 //  - groupId - The byte data representing a group ID (a byte marshalled id.ID).
-//              This can be pulled from a marshalled GroupReport.
+//    This can be pulled from a marshalled GroupReport.
 // Returns:
 //  - Group - The bindings-layer representation of a group.
 func (g *GroupChat) GetGroup(groupId []byte) (*Group, error) {
@@ -308,7 +242,7 @@ func (g *GroupChat) GetGroup(groupId []byte) (*Group, error) {
 	}
 
 	// Add to tracker and return Group object
-	return groupTrackerSingleton.make(grp), nil
+	return &Group{g: grp}, nil
 }
 
 // NumGroups returns the number of groups the user is a part of.
@@ -317,14 +251,13 @@ func (g *GroupChat) NumGroups() int {
 }
 
 ////////////////////////////////////////////////////////////////////////////////
-// Group Structure
+// Group Structure                                                            //
 ////////////////////////////////////////////////////////////////////////////////
 
 // Group structure contains the identifying and membership information of a
 // group chat.
 type Group struct {
-	g  gs.Group
-	id int
+	g gs.Group
 }
 
 // GetName returns the name set by the user for the group.
@@ -332,16 +265,11 @@ func (g *Group) GetName() []byte {
 	return g.g.Name
 }
 
-// GetID return the 33-byte unique group ID. This represents the id.ID object
+// GetID return the 33-byte unique group ID. This represents the id.ID object.
 func (g *Group) GetID() []byte {
 	return g.g.ID.Bytes()
 }
 
-// GetTrackedID returns the tracked ID of the Group object. This is used by the backend tracker.
-func (g *Group) GetTrackedID() int {
-	return g.id
-}
-
 // GetInitMessage returns initial message sent with the group request.
 func (g *Group) GetInitMessage() []byte {
 	return g.g.InitMessage
@@ -365,7 +293,26 @@ func (g *Group) GetCreatedMS() int64 {
 // All subsequent members are ordered by their ID.
 //
 // Returns:
-//  - []byte - a JSON marshalled version of the member list.
+//  - []byte - JSON marshalled [group.Membership], which is an array of
+//    [group.Member].
+//
+// Example JSON [group.Membership] return:
+//  [
+//    {
+//      "ID": "U4x/lrFkvxuXu59LtHLon1sUhPJSCcnZND6SugndnVID",
+//      "DhKey": {
+//        "Value": 3534334367214237261,
+//        "Fingerprint": 16801541511233098363
+//      }
+//    },
+//    {
+//      "ID": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD",
+//      "DhKey": {
+//        "Value": 7497468244883513247,
+//        "Fingerprint": 16801541511233098363
+//      }
+//    }
+//  ]
 func (g *Group) GetMembership() ([]byte, error) {
 	return json.Marshal(g.g.Members)
 }
@@ -375,19 +322,30 @@ func (g *Group) Serialize() []byte {
 	return g.g.Serialize()
 }
 
-//////////////////////////////////////////////////////////////////////////////////
-// Callbacks
-//////////////////////////////////////////////////////////////////////////////////
+// DeserializeGroup converts the results of Group.Serialize into a Group
+// so that its methods can be called.
+func DeserializeGroup(serializedGroupData []byte) (*Group, error) {
+	grp, err := gs.DeserializeGroup(serializedGroupData)
+	if err != nil {
+		return nil, err
+	}
+	return &Group{g: grp}, nil
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Callbacks                                                                  //
+////////////////////////////////////////////////////////////////////////////////
 
 // GroupRequest is a bindings-layer interface that handles a group reception.
 //
 // Parameters:
-//  - trackedGroupId - a bindings layer Group object.
+//  - g - a bindings layer Group object.
 type GroupRequest interface {
 	Callback(g *Group)
 }
 
 // GroupChatProcessor manages the handling of received group chat messages.
+// The decryptedMessage field will be a JSON marshalled GroupChatMessage.
 type GroupChatProcessor interface {
 	Process(decryptedMessage, msg, receptionId []byte, ephemeralId,
 		roundId int64, err error)
@@ -400,13 +358,53 @@ type groupChatProcessor struct {
 	bindingsCb GroupChatProcessor
 }
 
+// GroupChatMessage is the bindings layer representation of the
+// [groupChat.MessageReceive].
+//
+// GroupChatMessage Example JSON:
+//  {
+//    "GroupId": "AAAAAAAJlasAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE",
+//    "SenderId": "AAAAAAAAB8gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD",
+//    "MessageId": "Zm9ydHkgZml2ZQAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
+//    "Payload": "Zm9ydHkgZml2ZQ==",
+//    "Timestamp": 1663009269474079000
+//  }
+type GroupChatMessage struct {
+	// GroupId is the ID of the group that this message was sent on.
+	GroupId []byte
+
+	// SenderId is the ID of the sender of this message.
+	SenderId []byte
+
+	// MessageId is the ID of this group message.
+	MessageId []byte
+
+	// Payload is the content of the message.
+	Payload []byte
+
+	// Timestamp is the time this message was sent on.
+	Timestamp int64
+}
+
+// convertMessageReceive is a helper function which converts a
+// [groupChat.MessageReceive] to the bindings-layer representation GroupChatMessage.
+func convertMessageReceive(decryptedMsg gc.MessageReceive) GroupChatMessage {
+	return GroupChatMessage{
+		GroupId:   decryptedMsg.GroupID.Bytes(),
+		SenderId:  decryptedMsg.SenderID.Bytes(),
+		MessageId: decryptedMsg.ID.Bytes(),
+		Payload:   decryptedMsg.Payload,
+		Timestamp: decryptedMsg.Timestamp.UnixNano(),
+	}
+}
+
 // convertProcessor turns the input of a groupChat.Processor to the
 // binding-layer primitives equivalents within the GroupChatProcessor.Process.
 func convertGroupChatProcessor(decryptedMsg gc.MessageReceive, msg format.Message,
 	receptionID receptionID.EphemeralIdentity, round rounds.Round) (
 	decryptedMessage, message, receptionId []byte, ephemeralId, roundId int64, err error) {
 
-	decryptedMessage, err = json.Marshal(decryptedMsg)
+	decryptedMessage, err = json.Marshal(convertMessageReceive(decryptedMsg))
 	message = msg.Marshal()
 	receptionId = receptionID.Source.Marshal()
 	ephemeralId = receptionID.EphId.Int64()
@@ -432,16 +430,34 @@ func (gcp *groupChatProcessor) String() string {
 // GroupReport is returned when creating a new group and contains the ID of
 // the group, a list of rounds that the group requests were sent on, and the
 // status of the send operation.
+//
+// Example GroupReport JSON:
+//		{
+//			"Id": "AAAAAAAAAM0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE",
+//			"Rounds": [25, 64],
+//			"RoundURL": "https://dashboard.xx.network/rounds/25?xxmessenger=true",
+//			"Status": 1
+//		}
 type GroupReport struct {
 	Id []byte
 	RoundsList
-	Status int
+	RoundURL string
+	Status   int
 }
 
 // GroupSendReport is returned when sending a group message. It contains the
 // round ID sent on and the timestamp of the send operation.
+//
+// Example GroupSendReport JSON:
+//      {
+//  	"Rounds": [25,	64],
+//  	"RoundURL": "https://dashboard.xx.network/rounds/25?xxmessenger=true",
+//  	"Timestamp": 1662577352813112000,
+//  	"MessageID": "69ug6FA50UT2q6MWH3hne9PkHQ+H9DnEDsBhc0m0Aww="
+//	    }
 type GroupSendReport struct {
 	RoundsList
+	RoundURL  string
 	Timestamp int64
 	MessageID []byte
 }
diff --git a/bindings/identity.go b/bindings/identity.go
index f1b56803184de8491f3c93ad43d89008f6227bd4..c48bd0d18814ae65037ed0a0cfd715fb7b8210ee 100644
--- a/bindings/identity.go
+++ b/bindings/identity.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package bindings
 
@@ -26,16 +26,18 @@ import (
 //   "RSAPrivatePem":"LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFcFFJQkFBS0NBUUVBNU15dTdhYjBJOS9UL1BFUUxtd2x3ejZHV3FjMUNYemVIVXhoVEc4bmg1WWRWSXMxCmJ2THpBVjNOMDJxdXN6K2s4TVFEWjBtejMzdkswUmhPczZIY0NUSFdzTEpXRkE5WWpzWWlCRi9qTDd1bmd1ckIKL2tvK1JJSnNrWGFWaEZaazRGdERoRXhTNWY4RnR0Qmk1NmNLZmdJQlVKT3ozZi9qQllTMkxzMlJ6cWV5YXM3SApjV2RaME9TclBTT3BiYlViU1FPbS9LWnlweGZHU21yZ2oxRUZuU1dZZ2xGZTdUOTRPbHF5MG14QTV5clVXbHorCk9sK3hHbXpCNUp4WUFSMU9oMFQrQTk4RWMrTUZHNm43L1MraDdzRDgybGRnVnJmbStFTzRCdmFKeTRESGZGMWgKNnp6QnVnY25NUVFGc0dLeDFYWC9COTVMdUpPVjdyeXlDbzZGbHdJREFRQUJBb0lCQVFDaUh6OGNlcDZvQk9RTAphUzBVRitHeU5VMnlVcVRNTWtTWThoUkh1c09CMmFheXoybHZVb3RLUHBPbjZRSWRWVTJrcE4vY2dtY0lSb2x5CkhBMDRUOHJBWVNaRlVqaVlRajkzKzRFREpJYXd2Z0YyVEs1bFoyb3oxVTdreStncU82V0RMR2Z0Q0wvODVQWEIKa210aXhnUXpRV3g1RWcvemtHdm03eURBalQxeDloNytsRjJwNFlBam5kT2xTS0dmQjFZeTR1RXBQd0kwc1lWdgpKQWc0MEFxbllZUmt4emJPbmQxWGNjdEJFN2Z1VDdrWXhoeSs3WXYrUTJwVy9BYmh6NGlHOEY1MW9GMGZwV0czCmlISDhsVXZFTkp2SUZEVHZ0UEpESlFZalBRN3lUbGlGZUdrMXZUQkcyQkpQNExzVzhpbDZOeUFuRktaY1hOQ24KeHVCendiSlJBb0dCQVBUK0dGTVJGRHRHZVl6NmwzZmg3UjJ0MlhrMysvUmpvR3BDUWREWDhYNERqR1pVd1RGVQpOS2tQTTNjS29ia2RBYlBDb3FpL0tOOVBibk9QVlZ3R3JkSE9vSnNibFVHYmJGamFTUzJQMFZnNUVhTC9rT2dUCmxMMUdoVFpIUWk1VUlMM0p4M1Z3T0ZRQ3RQOU1UQlQ0UEQvcEFLbDg3VTJXN3JTY1dGV1ZGbFNkQW9HQkFPOFUKVmhHWkRpVGFKTWVtSGZIdVYrNmtzaUlsam9aUVVzeGpmTGNMZ2NjV2RmTHBqS0ZWTzJNN3NqcEJEZ0w4NmFnegorVk14ZkQzZ1l0SmNWN01aMVcwNlZ6TlNVTHh3a1dRY1hXUWdDaXc5elpyYlhCUmZRNUVjMFBlblVoWWVwVzF5CkpkTC8rSlpQeDJxSzVrQytiWU5EdmxlNWdpcjlDSGVzTlR5enVyckRBb0dCQUl0cTJnN1RaazhCSVFUUVNrZ24Kb3BkRUtzRW4wZExXcXlBdENtVTlyaWpHL2l2eHlXczMveXZDQWNpWm5VVEp0QUZISHVlbXVTeXplQ2g5QmRkegoyWkRPNUdqQVBxVHlQS3NudFlNZkY4UDczZ1NES1VSWWVFbHFDejdET0c5QzRzcitPK3FoN1B3cCtqUmFoK1ZiCkNuWllNMDlBVDQ3YStJYUJmbWRkaXpLbEFvR0JBSmo1dkRDNmJIQnNISWlhNUNJL1RZaG5YWXUzMkVCYytQM0sKMHF3VThzOCtzZTNpUHBla2Y4RjVHd3RuUU4zc2tsMk1GQWFGYldmeVFZazBpUEVTb0p1cGJzNXA1enNNRkJ1bwpncUZrVnQ0RUZhRDJweTVwM2tQbDJsZjhlZXVwWkZScGE0WmRQdVIrMjZ4eWYrNEJhdlZJeld3NFNPL1V4Q3crCnhqbTNEczRkQW9HQWREL0VOa1BjU004c1BCM3JSWW9MQ2twcUV2U0MzbVZSbjNJd3c1WFAwcDRRVndhRmR1ckMKYUhtSE1EekNrNEUvb0haQVhFdGZ2S2tRaUI4MXVYM2c1aVo4amdYUVhXUHRteTVIcVVhcWJYUTlENkxWc3B0egpKL3R4SWJLMXp5c1o2bk9IY1VoUUwyVVF6SlBBRThZNDdjYzVzTThEN3kwZjJ0QURTQUZNMmN3PQotLS0tLUVORCBSU0EgUFJJVkFURSBLRVktLS0tLQ==",
 //   "Salt":"4kk02v0NIcGtlobZ/xkxqWz8uH/ams/gjvQm14QT0dI=",
 //   "DHKeyPrivate":"eyJWYWx1ZSI6NDU2MDgzOTEzMjA0OTIyODA5Njg2MDI3MzQ0MzM3OTA0MzAyODYwMjM2NDk2NDM5NDI4NTcxMTMwNDMzOTQwMzgyMTIyMjY4OTQzNTMyMjIyMzc1MTkzNTEzMjU4MjA4MDA0NTczMDY4MjEwNzg2NDI5NjA1MjA0OTA3MjI2ODI5OTc3NTczMDkxODY0NTY3NDExMDExNjQxNCwiRmluZ2VycHJpbnQiOjE2ODAxNTQxNTExMjMzMDk4MzYzfQ=="
-//  }
+//   "E2eGrp": "eyJnZW4iOiIyIiwicHJpbWUiOiJlMmVlOTgzZDAzMWRjMWRiNmYxYTdhNjdkZjBlOWE4ZTU1NjFkYjhlOGQ0OTQxMzM5NGMwNDliN2E4YWNjZWRjMjk4NzA4ZjEyMTk1MWQ5Y2Y5MjBlYzVkMTQ2NzI3YWE0YWU1MzViMDkyMmM2ODhiNTViM2RkMmFlZGY2YzAxYzk0NzY0ZGFiOTM3OTM1YWE4M2JlMzZlNjc3NjA3MTNhYjQ0YTYzMzdjMjBlNzg2MTU3NWU3NDVkMzFmOGI5ZTlhZDg0MTIxMThjNjJhM2UyZTI5ZGY0NmIwODY0ZDBjOTUxYzM5NGE1Y2JiZGM2YWRjNzE4ZGQyYTNlMDQxMDIzZGJiNWFiMjNlYmI0NzQyZGU5YzE2ODdiNWIzNGZhNDhjMzUyMTYzMmM0YTUzMGU4ZmZiMWJjNTFkYWRkZjQ1M2IwYjI3MTdjMmJjNjY2OWVkNzZiNGJkZDVjOWZmNTU4ZTg4ZjI2ZTU3ODUzMDJiZWRiY2EyM2VhYzVhY2U5MjA5NmVlOGE2MDY0MmZiNjFlOGYzZDI0OTkwYjhjYjEyZWU0NDhlZWY3OGUxODRjNzI0MmRkMTYxYzc3MzhmMzJiZjI5YTg0MTY5ODk3ODgyNWI0MTExYjRiYzNlMWUxOTg0NTUwOTU5NTgzMzNkNzc2ZDhiMmJlZWVkM2ExYTFhMjIxYTZlMzdlNjY0YTY0YjgzOTgxYzQ2ZmZkZGMxYTQ1ZTNkNTIxMWFhZjhiZmJjMDcyNzY4YzRmNTBkN2Q3ODAzZDJkNGYyNzhkZTgwMTRhNDczMjM2MzFkN2UwNjRkZTgxYzBjNmJmYTQzZWYwZTY5OTg4NjBmMTM5MGI1ZDNmZWFjYWYxNjk2MDE1Y2I3OWMzZjljMmQ5M2Q5NjExMjBjZDBlNWYxMmNiYjY4N2VhYjA0NTI0MWY5Njc4OWMzOGU4OWQ3OTYxMzhlNjMxOWJlNjJlMzVkODdiMTA0OGNhMjhiZTM4OWI1NzVlOTk0ZGNhNzU1NDcxNTg0YTA5ZWM3MjM3NDJkYzM1ODczODQ3YWVmNDlmNjZlNDM4NzMifQ=="
+// }
 type ReceptionIdentity struct {
 	ID            []byte // User ID (base64)
 	RSAPrivatePem []byte // RSA Private key (PEM format)
 	Salt          []byte // Salt for identity (base64)
 	DHKeyPrivate  []byte // DH Private key
+	E2eGrp        []byte
 }
 
 // StoreReceptionIdentity stores the given identity in Cmix storage with the
-// given key.  This is the ideal way to securely store identities, as the caller
+// given key. This is the ideal way to securely store identities, as the caller
 // of this function is only required to store the given key separately rather
 // than the keying material.
 func StoreReceptionIdentity(key string, identity []byte, cmixId int) error {
@@ -77,7 +79,8 @@ func (c *Cmix) MakeReceptionIdentity() ([]byte, error) {
 }
 
 // MakeLegacyReceptionIdentity generates the legacy identity for receiving
-// messages.
+// messages. As with all legacy calls, this should primarily be used
+// for the xx messenger team.
 func (c *Cmix) MakeLegacyReceptionIdentity() ([]byte, error) {
 	ident, err := xxdk.MakeLegacyReceptionIdentity(c.api)
 	if err != nil {
@@ -90,17 +93,23 @@ func (c *Cmix) MakeLegacyReceptionIdentity() ([]byte, error) {
 // GetReceptionRegistrationValidationSignature returns the signature provided by
 // the xx network.
 func (c *Cmix) GetReceptionRegistrationValidationSignature() []byte {
-	return c.api.GetStorage().GetReceptionRegistrationValidationSignature()
+	regSig := c.api.GetStorage().GetReceptionRegistrationValidationSignature()
+	return regSig
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // Contact Functions                                                          //
 ////////////////////////////////////////////////////////////////////////////////
 
-// GetIDFromContact accepts a marshalled contact.Contact object and returns a
-// marshalled id.ID object.
-func GetIDFromContact(marshaled []byte) ([]byte, error) {
-	cnt, err := contact.Unmarshal(marshaled)
+// GetIDFromContact returns the ID in the [contact.Contact] object.
+//
+// Parameters:
+//  - marshaledContact - JSON marshalled bytes of [contact.Contact]
+//
+// Returns:
+//  - []byte - bytes of the [id.ID] object
+func GetIDFromContact(marshaledContact []byte) ([]byte, error) {
+	cnt, err := contact.Unmarshal(marshaledContact)
 	if err != nil {
 		return nil, err
 	}
@@ -108,10 +117,16 @@ func GetIDFromContact(marshaled []byte) ([]byte, error) {
 	return cnt.ID.Marshal(), nil
 }
 
-// GetPubkeyFromContact accepts a marshalled contact.Contact object and returns
-// a JSON marshalled large.Int DH public key.
-func GetPubkeyFromContact(marshaled []byte) ([]byte, error) {
-	cnt, err := contact.Unmarshal(marshaled)
+// GetPubkeyFromContact returns the DH public key in the [contact.Contact]
+// object.
+//
+// Parameters:
+//  - marshaledContact - JSON marshalled bytes of [contact.Contact]
+//
+// Returns:
+//  - []byte - JSON marshalled bytes of the [cyclic.Int] object
+func GetPubkeyFromContact(marshaledContact []byte) ([]byte, error) {
+	cnt, err := contact.Unmarshal(marshaledContact)
 	if err != nil {
 		return nil, err
 	}
@@ -123,67 +138,44 @@ func GetPubkeyFromContact(marshaled []byte) ([]byte, error) {
 // Fact Functions                                                             //
 ////////////////////////////////////////////////////////////////////////////////
 
-// Fact is an internal fact type for use in the bindings layer.
-//
-// JSON example:
-//  {
-//   "Fact": "Zezima",
-//   "Type": 0
-//  }
-type Fact struct {
-	Fact string
-	Type int
-}
-
 // SetFactsOnContact replaces the facts on the contact with the passed in facts
 // pass in empty facts in order to clear the facts.
 //
 // Parameters:
-//  - marshaled - JSON marshalled contact.Contact object
-//  - facts - JSON marshalled Fact object.
-func SetFactsOnContact(marshaled []byte, facts []byte) ([]byte, error) {
-	cnt, err := contact.Unmarshal(marshaled)
+//  - marshaledContact - the JSON marshalled bytes of [contact.Contact]
+//  - factListJSON - the JSON marshalled bytes of [fact.FactList]
+//
+// Returns:
+//  - []byte - marshalled bytes of the modified [contact.Contact]
+func SetFactsOnContact(marshaledContact []byte, factListJSON []byte) ([]byte, error) {
+	cnt, err := contact.Unmarshal(marshaledContact)
 	if err != nil {
 		return nil, err
 	}
 
-	factsList := make([]Fact, 0)
-	err = json.Unmarshal(facts, &factsList)
+	var factsList fact.FactList
+	err = json.Unmarshal(factListJSON, &factsList)
 	if err != nil {
 		return nil, err
 	}
 
-	realFactList := make(fact.FactList, 0, len(factsList))
-	for i := range factsList {
-		realFactList = append(realFactList, fact.Fact{
-			Fact: factsList[i].Fact,
-			T:    fact.FactType(factsList[i].Type),
-		})
-	}
+	cnt.Facts = factsList
 
-	cnt.Facts = realFactList
 	return cnt.Marshal(), nil
 }
 
-// GetFactsFromContact accepts a marshalled contact.Contact object and returns
-// its marshalled list of Fact objects.
-func GetFactsFromContact(marshaled []byte) ([]byte, error) {
-	cnt, err := contact.Unmarshal(marshaled)
+// GetFactsFromContact returns the fact list in the [contact.Contact] object.
+//
+// Parameters:
+//  - marshaledContact - the JSON marshalled bytes of [contact.Contact]
+//
+// Returns:
+//  - []byte - the JSON marshalled bytes of [fact.FactList]
+func GetFactsFromContact(marshaledContact []byte) ([]byte, error) {
+	cnt, err := contact.Unmarshal(marshaledContact)
 	if err != nil {
 		return nil, err
 	}
 
-	factsList := make([]Fact, len(cnt.Facts))
-	for i := range cnt.Facts {
-		factsList = append(factsList, Fact{
-			Fact: cnt.Facts[i].Fact,
-			Type: int(cnt.Facts[i].T),
-		})
-	}
-
-	factsListMarshaled, err := json.Marshal(&factsList)
-	if err != nil {
-		return nil, err
-	}
-	return factsListMarshaled, nil
+	return json.Marshal(&cnt.Facts)
 }
diff --git a/bindings/identity_test.go b/bindings/identity_test.go
index 662f1f5c000021def40a17a50d9c9646b8a78779..eeff0b1a83edb91a79526f4b7e4fb225fe9174a0 100644
--- a/bindings/identity_test.go
+++ b/bindings/identity_test.go
@@ -1,16 +1,14 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package bindings
 
 import (
 	"encoding/json"
-	"testing"
-
 	"gitlab.com/elixxir/crypto/cmix"
 	"gitlab.com/elixxir/crypto/cyclic"
 	dh "gitlab.com/elixxir/crypto/diffieHellman"
@@ -18,6 +16,7 @@ import (
 	"gitlab.com/xx_network/crypto/large"
 	"gitlab.com/xx_network/crypto/signature/rsa"
 	"gitlab.com/xx_network/primitives/id"
+	"testing"
 )
 
 func TestIdentity_JSON(t *testing.T) {
@@ -29,34 +28,21 @@ func TestIdentity_JSON(t *testing.T) {
 	dhpk := dh.GeneratePrivateKey(64, grp, rng)
 	dhpkJson, _ := dhpk.MarshalJSON()
 	op := make([]byte, 64)
+	e2eGrp, _ := getGroup().MarshalJSON()
 	_, _ = rng.Read(op)
 	identity := ReceptionIdentity{
 		ID:            uid.Marshal(),
 		RSAPrivatePem: rsa.CreatePrivateKeyPem(pk),
 		Salt:          salt,
 		DHKeyPrivate:  dhpkJson,
+		E2eGrp:        e2eGrp,
 	}
+
 	im, _ := json.Marshal(identity)
 	t.Log("Marshalled ReceptionIdentity object")
 	t.Log(string(im))
 }
 
-func TestFacts_JSON(t *testing.T) {
-	fl := []Fact{
-		{
-			Fact: "Zezima",
-			Type: 0,
-		},
-		{
-			Fact: "Zezima@osrs.org",
-			Type: 2,
-		},
-	}
-	flm, _ := json.Marshal(fl)
-	t.Log("Marshalled []Fact")
-	t.Log(string(flm))
-}
-
 func getGroup() *cyclic.Group {
 	return cyclic.NewGroup(
 		large.NewIntFromString("E2EE983D031DC1DB6F1A7A67DF0E9A8E5561DB8E8D4941"+
diff --git a/bindings/listener.go b/bindings/listener.go
index c19bca2fd3d1dfa72608f51b60c474f64cfa7b24..8eaf0faff2e58bb188a9451f624d2eae1926bd9c 100644
--- a/bindings/listener.go
+++ b/bindings/listener.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package bindings
 
@@ -62,6 +62,7 @@ type Message struct {
 
 	Encrypted bool
 	RoundId   int
+	RoundURL  string
 }
 
 // Hear is called to receive a message in the UI.
@@ -76,6 +77,7 @@ func (l listener) Hear(item receive.Message) {
 		Timestamp:   item.Timestamp.UnixNano(),
 		Encrypted:   item.Encrypted,
 		RoundId:     int(item.Round.ID),
+		RoundURL:    getRoundURL(item.Round.ID),
 	}
 	result, err := json.Marshal(&m)
 	if err != nil {
diff --git a/bindings/listener_test.go b/bindings/listener_test.go
index 92276c186e1d30ac8d91785df3a1ab8839cf0746..e06dd2b549a84ec650129158575ede3966036fa7 100644
--- a/bindings/listener_test.go
+++ b/bindings/listener_test.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package bindings
 
diff --git a/bindings/logging.go b/bindings/logging.go
index 6783d4b546f293862863110a85b16791dbf88baa..9b609f103e8d59e79b7ac5e8e2099d5cd1056b1b 100644
--- a/bindings/logging.go
+++ b/bindings/logging.go
@@ -1,16 +1,15 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 // logging.go contains bindings log control functions
 
 package bindings
 
 import (
-	"fmt"
 	"log"
 
 	"github.com/pkg/errors"
@@ -34,7 +33,7 @@ import (
 // The default log level without updates is INFO.
 func LogLevel(level int) error {
 	if level < 0 || level > 6 {
-		return errors.New(fmt.Sprintf("log level is not valid: log level: %d", level))
+		return errors.Errorf("log level is not valid: log level: %d", level)
 	}
 
 	threshold := jww.Threshold(level)
diff --git a/bindings/ndf.go b/bindings/ndf.go
index eb6a5c87d7c33ee968c6d005cb10ab96e7026968..605d5fa7ec6abdab136410893c14f5f06ff034f3 100644
--- a/bindings/ndf.go
+++ b/bindings/ndf.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package bindings
 
diff --git a/bindings/ndf_test.go b/bindings/ndf_test.go
index c453582b5d7eccee053de6f4d60cae5a345af3ed..5c565bb4b3965567b553bfd393b1a8fab8a102be 100644
--- a/bindings/ndf_test.go
+++ b/bindings/ndf_test.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package bindings
 
diff --git a/bindings/notifications.go b/bindings/notifications.go
new file mode 100644
index 0000000000000000000000000000000000000000..217accf1163a6d12d426a0ebd90f6902f9e05244
--- /dev/null
+++ b/bindings/notifications.go
@@ -0,0 +1,171 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
+package bindings
+
+import (
+	"encoding/json"
+	"gitlab.com/elixxir/client/cmix/message"
+	"gitlab.com/elixxir/primitives/notifications"
+)
+
+// NotificationReports is a list of [NotificationReport]s. This will be returned
+// via GetNotificationsReport as a JSON marshalled byte data.
+//
+// Example JSON:
+//  [
+//    {
+//      "ForMe": true,                                           // boolean
+//      "Type": "e2e",                                           // string
+//      "Source": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD" // bytes of id.ID encoded as base64 string
+//    },
+//    {
+//      "ForMe": true,
+//      "Type": "e2e",
+//      "Source": "AAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD"
+//    },
+//    {
+//      "ForMe": true,
+//      "Type": "e2e",
+//      "Source": "AAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD"
+//    }
+//  ]
+type NotificationReports []NotificationReport
+
+//  TODO: The table in the docstring below needs to be checked for completeness
+//   and/or accuracy to ensure descriptions/sources are still accurate (they are
+//   from the old implementation).
+
+// NotificationReport is the bindings' representation for notifications for
+// this user.
+//
+// Example NotificationReport JSON:
+//  {
+//    "ForMe": true,
+//    "Type": "e2e",
+//    "Source": "dGVzdGVyMTIzAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+//  }
+//
+// Given the Type, the Source value will have specific contextual meanings.
+// Below is a table that will define the contextual meaning of the Source field
+// given all possible Type fields.
+//
+//   TYPE     |     SOURCE         |    DESCRIPTION
+//  ----------+--------------------+--------------------------------------------------------
+//  "default" |  recipient user ID |  A message with no association.
+//  "request" |  sender user ID    |  A channel request has been received, from Source.
+//  "reset"   |  sender user ID    |  A channel reset has been received.
+//  "confirm" |  sender user ID    |  A channel request has been accepted.
+//  "silent"  |  sender user ID    |  A message where the user should not be notified.
+//  "e2e"     |  sender user ID    |  A reception of an E2E message.
+//  "group"   |  group ID          |  A reception of a group chat message.
+//  "endFT"   |  sender user ID    |  The last message sent confirming end of file transfer.
+//  "groupRQ" |  sender user ID    |  A request from Source to join a group chat.
+type NotificationReport struct {
+	// ForMe determines whether this value is for the user. If it is
+	// false, this report may be ignored.
+	ForMe bool
+	// Type is the type of notification. The list can be seen
+	Type string
+	// Source is the source of the notification.
+	Source []byte
+}
+
+// GetNotificationsReport parses the received notification data to determine which
+// notifications are for this user. // This returns the JSON-marshalled
+// NotificationReports.
+//
+// Parameters:
+//  - e2eID - e2e object ID in the tracker
+//  - notificationCSV - the notification data received from the
+//    notifications' server.
+//  - marshalledServices - the JSON-marshalled list of services the backend
+//    keeps track of. Refer to Cmix.TrackServices for information about this.
+//
+// Returns:
+//  - []byte - A JSON marshalled NotificationReports. Some NotificationReport's
+//    within in this structure may have their NotificationReport.ForMe
+//    set to false. These may be ignored.
+func GetNotificationsReport(e2eId int, notificationCSV string,
+	marshalledServices []byte) ([]byte, error) {
+	// Retrieve user
+	user, err := e2eTrackerSingleton.get(e2eId)
+	if err != nil {
+		return nil, err
+	}
+
+	serviceList := message.ServiceList{}
+	err = json.Unmarshal(marshalledServices, &serviceList)
+	if err != nil {
+		return nil, err
+	}
+
+	// Retrieve the services for this user
+	services := serviceList[*user.api.GetReceptionIdentity().ID]
+
+	// Decode notifications' server data
+	notificationList, err := notifications.DecodeNotificationsCSV(notificationCSV)
+	if err != nil {
+		return nil, err
+	}
+
+	// Construct  a report list
+	reportList := make([]*NotificationReport, len(notificationList))
+
+	// Iterate over data provided by server
+	for i := range notificationList {
+		notifData := notificationList[i]
+
+		// Iterate over all services
+		for j := range services {
+			// Pull data from services and from notification data
+			service := services[j]
+			messageHash := notifData.MessageHash
+			hash := service.HashFromMessageHash(notifData.MessageHash)
+
+			// Check if this notification data is recognized by
+			// this service, ie "ForMe"
+			if service.ForMeFromMessageHash(messageHash, hash) {
+				// Fill report list with service data
+				reportList[i] = &NotificationReport{
+					ForMe:  true,
+					Type:   service.Tag,
+					Source: service.Identifier,
+				}
+			}
+		}
+	}
+
+	return json.Marshal(reportList)
+}
+
+// RegisterForNotifications allows a client to register for push notifications.
+// The token is a firebase messaging token.
+//
+// Parameters:
+//  - e2eId - ID of the E2E object in the E2E tracker
+func RegisterForNotifications(e2eId int, token string) error {
+	user, err := e2eTrackerSingleton.get(e2eId)
+	if err != nil {
+		return err
+	}
+
+	return user.api.RegisterForNotifications(token)
+}
+
+// UnregisterForNotifications turns off notifications for this client.
+//
+// Parameters:
+//  - e2eId - ID of the E2E object in the E2E tracker
+func UnregisterForNotifications(e2eId int) error {
+	user, err := e2eTrackerSingleton.get(e2eId)
+	if err != nil {
+		return err
+	}
+
+	return user.api.UnregisterForNotifications()
+}
diff --git a/bindings/notifications_test.go b/bindings/notifications_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..91d2974593719c9094def579d34b74a01325ac74
--- /dev/null
+++ b/bindings/notifications_test.go
@@ -0,0 +1,35 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
+package bindings
+
+import (
+	"encoding/json"
+	"fmt"
+	"gitlab.com/elixxir/client/e2e/ratchet"
+	"gitlab.com/xx_network/primitives/id"
+	"testing"
+)
+
+func TestNotificationReport(t *testing.T) {
+	reports := []NotificationReport{}
+
+	for i := 0; i < 3; i++ {
+		nr := NotificationReport{
+			ForMe:  true,
+			Type:   ratchet.E2e,
+			Source: id.NewIdFromUInt(uint64(i), id.User, t).Bytes(),
+		}
+
+		reports = append(reports, nr)
+	}
+
+	nrs := NotificationReports(reports)
+
+	marshal, _ := json.Marshal(nrs)
+	fmt.Printf("%s\n", marshal)
+}
diff --git a/bindings/params.go b/bindings/params.go
index 2b0cdd18c82d16c2a7a3f0b5570532d26bf87b23..f44c71edd2a13c0ae59a928f276619c43a2c1a2e 100644
--- a/bindings/params.go
+++ b/bindings/params.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 // params.go provides functions for getting and setting parameters in bindings.
 
@@ -66,8 +66,8 @@ func GetDefaultSingleUseParams() []byte {
 }
 
 // GetDefaultE2eFileTransferParams returns a JSON serialized object with all the
-// e2e file transfer parameters and their default values. Call this function and modify
-// the JSON to change single use settings.
+// E2E file transfer parameters and their default values. Call this function and
+// modify the JSON to change single use settings.
 func GetDefaultE2eFileTransferParams() []byte {
 	defaultParams := e2eFileTransfer.DefaultParams()
 	data, err := defaultParams.MarshalJSON()
@@ -77,27 +77,42 @@ func GetDefaultE2eFileTransferParams() []byte {
 	return data
 }
 
+// parseE2eFileTransferParams is a helper function which parses a JSON
+// marshalled [e2eFileTransfer.Params].
 func parseE2eFileTransferParams(data []byte) (e2eFileTransfer.Params, error) {
 	p := &e2eFileTransfer.Params{}
 	return *p, p.UnmarshalJSON(data)
 }
 
+// parseSingleUseParams is a helper function which parses a JSON marshalled
+// [single.RequestParams].
 func parseSingleUseParams(data []byte) (single.RequestParams, error) {
 	p := &single.RequestParams{}
 	return *p, p.UnmarshalJSON(data)
 }
 
+// parseFileTransferParams is a helper function which parses a JSON marshalled
+// [fileTransfer.Params].
 func parseFileTransferParams(data []byte) (fileTransfer.Params, error) {
 	p := &fileTransfer.Params{}
 	return *p, p.UnmarshalJSON(data)
 }
 
+// parseCMixParams is a helper function which parses a JSON marshalled
+// [xxdk.CMIXParams].
 func parseCMixParams(data []byte) (xxdk.CMIXParams, error) {
+	if len(data) == 0 {
+		jww.WARN.Printf("cMix params not specified, using defaults...")
+		data = GetDefaultCMixParams()
+	}
+
 	p := &xxdk.CMIXParams{}
 	err := p.Unmarshal(data)
 	return *p, err
 }
 
+// parseE2EParams is a helper function which parses a JSON marshalled
+// [xxdk.E2EParams].
 func parseE2EParams(data []byte) (xxdk.E2EParams, error) {
 	p := &xxdk.E2EParams{}
 	err := p.Unmarshal(data)
diff --git a/bindings/restlike.go b/bindings/restlike.go
index e3c87e1d8279f60833ae91a8e49f32597fcf8352..bebe90bc88fe54f8d8f35c652f67830b3259562d 100644
--- a/bindings/restlike.go
+++ b/bindings/restlike.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package bindings
 
@@ -107,7 +107,7 @@ func RestlikeRequest(
 //
 // Returns:
 //  - []byte - JSON marshalled RestlikeMessage
-func RestlikeRequestAuth(cmixId int, authConnectionID int, request,
+func RestlikeRequestAuth(cmixId, authConnectionID int, request,
 	e2eParamsJSON []byte) ([]byte, error) {
 	if len(e2eParamsJSON) == 0 {
 		jww.WARN.Printf("restlike params unspecified, using defaults")
diff --git a/bindings/restlikeSingle.go b/bindings/restlikeSingle.go
index 76431501a3f9393b8e954ca81ac0d9f004653ba9..c71d0e05b4c02f74354957671e40f0f642565bdb 100644
--- a/bindings/restlikeSingle.go
+++ b/bindings/restlikeSingle.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package bindings
 
diff --git a/bindings/secrets.go b/bindings/secrets.go
index 6086282de043b535a769a6c5e5a5c788a156a081..41f16598dc7b283c59bf1da2a6d1189c5b49fc94 100644
--- a/bindings/secrets.go
+++ b/bindings/secrets.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package bindings
 
diff --git a/bindings/secrets_test.go b/bindings/secrets_test.go
index 60b03a2d42b8b564e4dbf134aab92c4cf189e401..41e590ec756bc1f4eb2981a2df44995d10b2c861 100644
--- a/bindings/secrets_test.go
+++ b/bindings/secrets_test.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package bindings
 
diff --git a/bindings/single.go b/bindings/single.go
index bb1efe57b0821fb1f1445c0fbf06ae7ce8ec666a..d6625cd71d8fe027fa2a64ca1b146d30e6f6eef0 100644
--- a/bindings/single.go
+++ b/bindings/single.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package bindings
 
@@ -62,14 +62,15 @@ func TransmitSingleUse(e2eID int, recipient []byte, tag string, payload,
 	}
 	sr := SingleUseSendReport{
 		EphID:       eid.EphId.Int64(),
-		ReceptionID: eid.Source.Marshal(),
+		ReceptionID: eid.Source,
 		RoundsList:  makeRoundsList(rids...),
+		RoundURL:    getRoundURL(rids[0]),
 	}
 	return json.Marshal(sr)
 }
 
-// Listen starts a single-use listener on a given tag using the passed in e2e object
-// and SingleUseCallback func.
+// Listen starts a single-use listener on a given tag using the passed in E2e
+// object and SingleUseCallback func.
 //
 // Parameters:
 //  - e2eID - ID of the e2e object in the tracker
@@ -85,11 +86,11 @@ func Listen(e2eID int, tag string, cb SingleUseCallback) (Stopper, error) {
 	}
 
 	suListener := singleUseListener{scb: cb}
-	dhpk, err := e2eCl.api.GetReceptionIdentity().GetDHKeyPrivate()
+	dhPk, err := e2eCl.api.GetReceptionIdentity().GetDHKeyPrivate()
 	if err != nil {
 		return nil, err
 	}
-	l := single.Listen(tag, e2eCl.api.GetReceptionIdentity().ID, dhpk,
+	l := single.Listen(tag, e2eCl.api.GetReceptionIdentity().ID, dhPk,
 		e2eCl.api.GetCmix(), e2eCl.api.GetStorage().GetE2EGroup(), suListener)
 	return &stopper{l: l}, nil
 }
@@ -99,15 +100,17 @@ func Listen(e2eID int, tag string, cb SingleUseCallback) (Stopper, error) {
 // SingleUseSendReport is the bindings-layer struct used to represent
 // information returned by single.TransmitRequest.
 //
-// JSON example:
+// SingleUseSendReport JSON example:
 //  {
 //   "Rounds":[1,5,9],
-//   "EphID":{"EphId":[0,0,0,0,0,0,3,89],
-//   "Source":"emV6aW1hAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD"}
+//   "RoundURL": "https://dashboard.xx.network/rounds/25?xxmessenger=true",
+//   "EphID":1655533,
+//   "ReceptionID":"emV6aW1hAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD"}
 //  }
 type SingleUseSendReport struct {
 	RoundsList
-	ReceptionID []byte
+	RoundURL    string
+	ReceptionID *id.ID
 	EphID       int64
 }
 
@@ -115,18 +118,20 @@ type SingleUseSendReport struct {
 // information passed to the single.Response callback interface in response to
 // single.TransmitRequest.
 //
-// JSON example:
+// SingleUseResponseReport JSON example:
 //  {
 //   "Rounds":[1,5,9],
+//   "RoundURL": "https://dashboard.xx.network/rounds/25?xxmessenger=true",
 //   "Payload":"rSuPD35ELWwm5KTR9ViKIz/r1YGRgXIl5792SF8o8piZzN6sT4Liq4rUU/nfOPvQEjbfWNh/NYxdJ72VctDnWw==",
-//   "ReceptionID":{"EphId":[0,0,0,0,0,0,3,89],
-//   "Source":"emV6aW1hAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD"},
-//   "Err":null
+//   "EphID":1655533,
+//   "ReceptionID":"emV6aW1hAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD"},
+//   "Err":"",
 //  }
 type SingleUseResponseReport struct {
 	RoundsList
+	RoundURL    string
 	Payload     []byte
-	ReceptionID []byte
+	ReceptionID *id.ID
 	EphID       int64
 	Err         error
 }
@@ -134,27 +139,30 @@ type SingleUseResponseReport struct {
 // SingleUseCallbackReport is the bindings-layer struct used to represent
 // single -use messages received by a callback passed into single.Listen.
 //
-// JSON example:
-//  {
-//   "Rounds":[1,5,9],
-//   "Payload":"rSuPD35ELWwm5KTR9ViKIz/r1YGRgXIl5792SF8o8piZzN6sT4Liq4rUU/nfOPvQEjbfWNh/NYxdJ72VctDnWw==",
-//   "Partner":"emV6aW1hAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD",
-//   "EphID":{"EphId":[0,0,0,0,0,0,3,89],
-//   "Source":"emV6aW1hAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD"}
-//  }
+// SingleUseCallbackReport JSON example:
+//    {
+//      "Rounds":[1,5,9],
+//      "RoundURL": "https://dashboard.xx.network/rounds/25?xxmessenger=true",
+//      "Payload":"rSuPD35ELWwm5KTR9ViKIz/r1YGRgXIl5792SF8o8piZzN6sT4Liq4rUU/nfOPvQEjbfWNh/NYxdJ72VctDnWw==",
+//      "Partner":"emV6aW1hAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD",
+//      "EphID":1655533,
+//      "ReceptionID":"emV6aW1hAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD"}
+//    }
 type SingleUseCallbackReport struct {
 	RoundsList
+	RoundURL    string
 	Payload     []byte
 	Partner     *id.ID
 	EphID       int64
-	ReceptionID []byte
+	ReceptionID *id.ID
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // Function Types                                                             //
 ////////////////////////////////////////////////////////////////////////////////
 
-// Stopper is a public interface returned by Listen, allowing users to stop the registered listener.
+// Stopper is a public interface returned by Listen, allowing users to stop the
+// registered listener.
 type Stopper interface {
 	Stop()
 }
@@ -164,8 +172,8 @@ type Stopper interface {
 //
 // Parameters:
 //  - callbackReport - the JSON marshalled bytes of the SingleUseCallbackReport
-//    object, which can be passed into WaitForRoundResult to see if the send
-//    succeeded.
+//    object, which can be passed into Cmix.WaitForRoundResult to see if the
+//    send operation succeeded.
 type SingleUseCallback interface {
 	Callback(callbackReport []byte, err error)
 }
@@ -175,8 +183,8 @@ type SingleUseCallback interface {
 //
 // Parameters:
 //  - callbackReport - the JSON marshalled bytes of the SingleUseResponseReport
-//    object, which can be passed into WaitForRoundResult to see if the send
-//    succeeded.
+//    object, which can be passed into Cmix.WaitForRoundResult to see if the
+//    send operation succeeded.
 type SingleUseResponse interface {
 	Callback(responseReport []byte, err error)
 }
@@ -207,9 +215,10 @@ func (sl singleUseListener) Callback(
 	scr := SingleUseCallbackReport{
 		Payload:     req.GetPayload(),
 		RoundsList:  makeRoundsList(rids...),
+		RoundURL:    getRoundURL(rids[0]),
 		Partner:     req.GetPartner(),
 		EphID:       eid.EphId.Int64(),
-		ReceptionID: eid.Source.Marshal(),
+		ReceptionID: eid.Source,
 	}
 
 	sl.scb.Callback(json.Marshal(scr))
@@ -245,7 +254,8 @@ func (sr singleUseResponse) Callback(payload []byte,
 	}
 	sendReport := SingleUseResponseReport{
 		RoundsList:  makeRoundsList(rids...),
-		ReceptionID: receptionID.Source.Marshal(),
+		RoundURL:    getRoundURL(rids[0]),
+		ReceptionID: receptionID.Source,
 		EphID:       receptionID.EphId.Int64(),
 		Payload:     payload,
 		Err:         err,
diff --git a/bindings/single_test.go b/bindings/single_test.go
index a262a40738afe4ce73fc565ddaf259663f9d3a2e..1f34d616f3af0e447b472e6675472f800131babf 100644
--- a/bindings/single_test.go
+++ b/bindings/single_test.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package bindings
 
@@ -36,7 +36,7 @@ func TestSingleUseJsonMarshals(t *testing.T) {
 	sendReport := SingleUseSendReport{
 		RoundsList:  rl,
 		EphID:       ephId.EphId.Int64(),
-		ReceptionID: ephId.Source.Marshal(),
+		ReceptionID: ephId.Source,
 	}
 	srm, err := json.Marshal(sendReport)
 	if err != nil {
@@ -48,7 +48,7 @@ func TestSingleUseJsonMarshals(t *testing.T) {
 	responseReport := SingleUseResponseReport{
 		RoundsList:  rl,
 		Payload:     payload,
-		ReceptionID: ephId.Source.Marshal(),
+		ReceptionID: ephId.Source,
 		EphID:       ephId.EphId.Int64(),
 		Err:         nil,
 	}
@@ -64,7 +64,7 @@ func TestSingleUseJsonMarshals(t *testing.T) {
 		Payload:     payload,
 		Partner:     rid,
 		EphID:       ephId.EphId.Int64(),
-		ReceptionID: ephId.Source.Marshal(),
+		ReceptionID: ephId.Source,
 	}
 	crm, err := json.Marshal(callbackReport)
 	if err != nil {
diff --git a/bindings/ud.go b/bindings/ud.go
index 6ce8f8b3af073057e210675ff3203ef5ba364746..976321c5b33b5fd964b37dfd4c3aa5e97be66cac 100644
--- a/bindings/ud.go
+++ b/bindings/ud.go
@@ -1,14 +1,15 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package bindings
 
 import (
 	"encoding/json"
+	"fmt"
 	"github.com/pkg/errors"
 	jww "github.com/spf13/jwalterweatherman"
 	"gitlab.com/elixxir/client/single"
@@ -105,34 +106,77 @@ type UdNetworkStatus interface {
 // Manager functions                                                          //
 ////////////////////////////////////////////////////////////////////////////////
 
-// NewOrLoadUd loads an existing Manager from storage or creates a
-// new one if there is no extant storage information. Parameters need be provided
-// to specify how to connect to the User Discovery service. These parameters may be used
-// to contact either the UD server hosted by the xx network team or a custom
-// third-party operated server. For the former, all the information may be pulled from the
-// NDF using the bindings.
+// IsRegisteredWithUD is a function which checks the internal state
+// files to determine if a user has registered with UD in the past.
+//
+// Parameters:
+//  - e2eID -  REQUIRED. The tracked e2e object ID. This can be retrieved using [E2e.GetID].
+//
+// Returns:
+//   - bool - A boolean representing true if the user has been registered with UD already
+//            or false if it has not been registered already.
+//  - error - An error should only be returned if the internal tracker failed to retrieve an
+//            E2e object given the e2eId. If an error was returned, the registration state check
+//            was not performed properly, and the boolean returned should be ignored.
+func IsRegisteredWithUD(e2eId int) (bool, error) {
+
+	// Get user from singleton
+	user, err := e2eTrackerSingleton.get(e2eId)
+	if err != nil {
+		return false, err
+	}
+
+	return ud.IsRegistered(user.api.GetStorage().GetKV()), nil
+}
+
+// NewOrLoadUd loads an existing UserDiscovery from storage or creates a new
+// UserDiscovery if there is no storage data. Regardless of storage state,
+// the UserDiscovery object returned will be registered with the
+// User Discovery service. If the user is not already registered, a call
+// to register will occur internally. If the user is already registered,
+// this call will simply load state and return to you a UserDiscovery object.
+// Some parameters are required for registering with the service, but are not required
+// if the user is already registered. These will be noted in the parameters section as
+// "SEMI-REQUIRED".
+//
+// Certain parameters are required every call to this function. These parameters are listed below
+// as "REQUIRED". For example, parameters need be provided to specify how to connect to the
+// User Discovery service. These parameters specifically may be used to contact either the UD
+// server hosted by the xx network team or a custom third-party operated server. For the former,
+// all the information may be fetched from the NDF using the bindings. These fetch
+// methods are detailed in the parameters section.
 //
 // Params
-//  - e2eID - e2e object ID in the tracker
-//  - follower - network follower func wrapped in UdNetworkStatus
-//  - username - the username the user wants to register with UD.
-//    If the user is already registered, this field may be blank
-//  - networkValidationSig is a signature provided by the network (i.e. the client registrar).
-//    This may be nil, however UD may return an error in some cases (e.g. in a production level
-//    environment).
-//  - cert is the TLS certificate for the UD server this call will connect with.
-//    You may use the UD server run by the xx network team by using E2e.GetUdCertFromNdf.
-//  - contactFile is the data within a marshalled contact.Contact. This represents the
+//  - e2eID -  REQUIRED. The tracked e2e object ID. This is returned by [E2e.GetID].
+//  - follower - REQUIRED. Network follower function. This will check if the network
+//    follower is running.
+//  - username - SEMI-REQUIRED. The username the user wants to register with UD.
+//    If the user is already registered, this field may be blank. If the user is not
+//    already registered, these field must be populated with a username that meets the
+//    requirements of the UD service. For example, in the xx network's UD service,
+//    the username must not be registered by another user.
+//  - registrationValidationSignature - SEMI-REQUIRED. A signature provided by the xx network
+//    (i.e. the client registrar). If the user is not already registered, this field is required
+//    in order to register with the xx network. This may be nil if the user is already registered
+//    or connecting to a third-party UD service unassociated with the xx network.
+//  - cert - REQUIRED. The TLS certificate for the UD server this call will connect with.
+//    If this is nil, you may not contact the UD server hosted by the xx network.
+//    Third-party services may vary.
+//    You may use the UD server run by the xx network team by using [E2e.GetUdCertFromNdf].
+//  - contactFile - REQUIRED. The data within a marshalled [contact.Contact]. This represents the
 //    contact file of the server this call will connect with.
-//    You may use the UD server run by the xx network team by using E2e.GetUdContactFromNdf.
-//  - address is the IP address of the UD server this call will connect with.
-//    You may use the UD server run by the xx network team by using E2e.GetUdAddressFromNdf.
+//    If this is nil, you may not contact the UD server hosted by the xx network.
+//    Third-party services may vary.
+//    You may use the UD server run by the xx network team by using [E2e.GetUdContactFromNdf].
+//  - address - REQUIRED. The IP address of the UD server this call will connect with.
+//    You may use the UD server run by the xx network team by using [E2e.GetUdAddressFromNdf].
+//    If this is nil, you may not contact the UD server hosted by the xx network.
+//    Third-party services may vary.
 //
 // Returns
 //  - A Manager object which is registered to the specified UD service.
-func NewOrLoadUd(e2eID int, follower UdNetworkStatus,
-	username string, registrationValidationSignature,
-	cert, contactFile []byte, address string) (
+func NewOrLoadUd(e2eID int, follower UdNetworkStatus, username string,
+	registrationValidationSignature, cert, contactFile []byte, address string) (
 	*UserDiscovery, error) {
 
 	// Get user from singleton
@@ -165,17 +209,24 @@ func NewOrLoadUd(e2eID int, follower UdNetworkStatus,
 // Parameters:
 //  - e2eID - e2e object ID in the tracker
 //  - follower - network follower func wrapped in UdNetworkStatus
-//  - emailFactJson - nullable JSON marshalled email fact.Fact
-//  - phoneFactJson - nullable JSON marshalled phone fact.Fact
-//  - cert is the TLS certificate for the UD server this call will connect with.
-//    You may use the UD server run by the xx network team by using E2e.GetUdCertFromNdf.
-//  - contactFile is the data within a marshalled contact.Contact. This represents the
-//    contact file of the server this call will connect with.
-//    You may use the UD server run by the xx network team by using E2e.GetUdContactFromNdf.
-//  - address is the IP address of the UD server this call will connect with.
-//    You may use the UD server run by the xx network team by using E2e.GetUdAddressFromNdf.
-func NewUdManagerFromBackup(e2eID int, follower UdNetworkStatus, emailFactJson,
-	phoneFactJson []byte, cert, contactFile []byte, address string) (*UserDiscovery, error) {
+//  - username - The username this user registered with initially. This should
+//               not be nullable, and be JSON marshalled as retrieved from
+//               UserDiscovery.GetFacts().
+//  - emailFactJson - nullable JSON marshalled email [fact.Fact]
+//  - phoneFactJson - nullable JSON marshalled phone [fact.Fact]
+//  - cert - the TLS certificate for the UD server this call will connect with.
+//    You may use the UD server run by the xx network team by using
+//    E2e.GetUdCertFromNdf.
+//  - contactFile - the data within a marshalled contact.Contact. This
+//    represents the contact file of the server this call will connect with. You
+//    may use the UD server run by the xx network team by using
+//    E2e.GetUdContactFromNdf.
+//  - address - the IP address of the UD server this call will connect with. You
+//    may use the UD server run by the xx network team by using
+//    E2e.GetUdAddressFromNdf.
+func NewUdManagerFromBackup(e2eID int, follower UdNetworkStatus,
+	usernameJson, emailFactJson, phoneFactJson,
+	cert, contactFile []byte, address string) (*UserDiscovery, error) {
 
 	// Get user from singleton
 	user, err := e2eTrackerSingleton.get(e2eID)
@@ -183,7 +234,9 @@ func NewUdManagerFromBackup(e2eID int, follower UdNetworkStatus, emailFactJson,
 		return nil, err
 	}
 
-	var email, phone fact.Fact
+	var email, phone, username fact.Fact
+
+	// Parse email if non-nil
 	if emailFactJson != nil {
 		err = json.Unmarshal(emailFactJson, &email)
 		if err != nil {
@@ -191,6 +244,7 @@ func NewUdManagerFromBackup(e2eID int, follower UdNetworkStatus, emailFactJson,
 		}
 	}
 
+	// Parse phone if non-nil
 	if phoneFactJson != nil {
 		err = json.Unmarshal(phoneFactJson, &phone)
 		if err != nil {
@@ -198,13 +252,19 @@ func NewUdManagerFromBackup(e2eID int, follower UdNetworkStatus, emailFactJson,
 		}
 	}
 
+	// Parse username
+	err = json.Unmarshal(usernameJson, &username)
+	if err != nil {
+		return nil, err
+	}
+
 	UdNetworkStatusFn := func() xxdk.Status {
 		return xxdk.Status(follower.UdNetworkStatus())
 	}
 
 	u, err := ud.NewManagerFromBackup(
 		user.api, user.api.GetComms(), UdNetworkStatusFn,
-		email, phone,
+		username, email, phone,
 		cert, contactFile, address)
 	if err != nil {
 		return nil, err
@@ -213,7 +273,7 @@ func NewUdManagerFromBackup(e2eID int, follower UdNetworkStatus, emailFactJson,
 	return udTrackerSingleton.make(u), nil
 }
 
-// GetFacts returns a JSON marshalled list of fact.Fact objects that exist
+// GetFacts returns a JSON marshalled list of [fact.Fact] objects that exist
 // within the Store's registeredFacts map.
 func (ud *UserDiscovery) GetFacts() []byte {
 	jsonData, err := json.Marshal(ud.api.GetFacts())
@@ -229,9 +289,9 @@ func (ud *UserDiscovery) GetContact() ([]byte, error) {
 	return ud.api.GetContact().Marshal(), nil
 }
 
-// ConfirmFact confirms a fact first registered via AddFact. The confirmation ID
-// comes from AddFact while the code will come over the associated
-// communications system.
+// ConfirmFact confirms a fact first registered via SendRegisterFact. The
+// confirmation ID comes from SendRegisterFact while the code will come over the
+// associated communications system.
 func (ud *UserDiscovery) ConfirmFact(confirmationID, code string) error {
 	return ud.api.ConfirmFact(confirmationID, code)
 }
@@ -246,7 +306,7 @@ func (ud *UserDiscovery) ConfirmFact(confirmationID, code string) error {
 // along with the code to finalize the fact.
 //
 // Parameters:
-//  - factJson - a JSON marshalled fact.Fact
+//  - factJson - a JSON marshalled [fact.Fact]
 func (ud *UserDiscovery) SendRegisterFact(factJson []byte) (string, error) {
 	var f fact.Fact
 	err := json.Unmarshal(factJson, &f)
@@ -262,7 +322,7 @@ func (ud *UserDiscovery) SendRegisterFact(factJson []byte) (string, error) {
 // be associated with this user.
 //
 // Parameters:
-//  - factJson - a JSON marshalled fact.Fact
+//  - factJson - a JSON marshalled [fact.Fact]
 func (ud *UserDiscovery) PermanentDeleteAccount(factJson []byte) error {
 	var f fact.Fact
 	err := json.Unmarshal(factJson, &f)
@@ -277,7 +337,7 @@ func (ud *UserDiscovery) PermanentDeleteAccount(factJson []byte) error {
 // passed in is not UD service does not associate this fact with this user.
 //
 // Parameters:
-//  - factJson - a JSON marshalled fact.Fact
+//  - factJson - a JSON marshalled [fact.Fact]
 func (ud *UserDiscovery) RemoveFact(factJson []byte) error {
 	var f fact.Fact
 	err := json.Unmarshal(factJson, &f)
@@ -309,13 +369,14 @@ type UdLookupCallback interface {
 // Parameters:
 //  - e2eID - e2e object ID in the tracker
 //  - udContact - the marshalled bytes of the contact.Contact object
-//  - lookupId - the marshalled bytes of the id.ID object for the user
-//    that LookupUD will look up.
+//  - lookupId - the marshalled bytes of the id.ID object for the user that
+//    LookupUD will look up.
 //  - singleRequestParams - the JSON marshalled bytes of single.RequestParams
 //
 // Returns:
 //  - []byte - the JSON marshalled bytes of the SingleUseSendReport object,
-//    which can be passed into WaitForRoundResult to see if the send succeeded.
+//    which can be passed into Cmix.WaitForRoundResult to see if the send
+//    succeeded.
 func LookupUD(e2eID int, udContact []byte, cb UdLookupCallback,
 	lookupId []byte, singleRequestParamsJSON []byte) ([]byte, error) {
 
@@ -352,13 +413,141 @@ func LookupUD(e2eID int, udContact []byte, cb UdLookupCallback,
 
 	sr := SingleUseSendReport{
 		EphID:       eid.EphId.Int64(),
-		ReceptionID: eid.Source.Marshal(),
+		ReceptionID: eid.Source,
 		RoundsList:  makeRoundsList(rids...),
+		RoundURL:    getRoundURL(rids[0]),
 	}
 
 	return json.Marshal(sr)
 }
 
+////////////////////////////////////////////////////////////////////////////////
+// User Discovery MultiLookup                                                      //
+////////////////////////////////////////////////////////////////////////////////
+
+// UdMultiLookupCallback contains the callback called by MultiLookupUD that returns the
+// contacts which match the passed in IDs.
+//
+// Parameters:
+//  - contactListJSON - the JSON marshalled bytes of []contact.Contact, or nil
+//    if an error occurs.
+//
+//   JSON Example:
+//   {
+//  	"<xxc(2)F8dL9EC6gy+RMJuk3R+Au6eGExo02Wfio5cacjBcJRwDEgB7Ugdw/BAr6RkCABkWAFV1c2VybmFtZTA7c4LzV05sG+DMt+rFB0NIJg==xxc>",
+//  	"<xxc(2)eMhAi/pYkW5jCmvKE5ZaTglQb+fTo1D8NxVitr5CCFADEgB7Ugdw/BAr6RoCABkWAFV1c2VybmFtZTE7fElAa7z3IcrYrrkwNjMS2w==xxc>",
+//  	"<xxc(2)d7RJTu61Vy1lDThDMn8rYIiKSe1uXA/RCvvcIhq5Yg4DEgB7Ugdw/BAr6RsCABkWAFV1c2VybmFtZTI7N3XWrxIUpR29atpFMkcR6A==xxc>"
+//	}
+//  - failedIDs - JSON marshalled list of []*id.ID objects which failed lookup
+//  - err - any errors that occurred in the multilookup.
+type UdMultiLookupCallback interface {
+	Callback(contactListJSON []byte, failedIDs []byte, err error)
+}
+
+type lookupResp struct {
+	id      *id.ID
+	contact contact.Contact
+	err     error
+}
+
+// MultiLookupUD returns the public key of all passed in IDs as known by the
+// user discovery system or returns by the timeout.
+//
+// Parameters:
+//  - e2eID - e2e object ID in the tracker
+//  - udContact - the marshalled bytes of the contact.Contact object
+//  - lookupIds - JSON marshalled list of []*id.ID object for the users that
+//    MultiLookupUD will look up.
+//  - singleRequestParams - the JSON marshalled bytes of single.RequestParams
+//
+// Returns:
+//  - []byte - the JSON marshalled bytes of the SingleUseSendReport object,
+//    which can be passed into Cmix.WaitForRoundResult to see if the send
+//    succeeded.
+func MultiLookupUD(e2eID int, udContact []byte, cb UdMultiLookupCallback,
+	lookupIds []byte, singleRequestParamsJSON []byte) error {
+
+	// Get user from singleton
+	user, err := e2eTrackerSingleton.get(e2eID)
+	if err != nil {
+		return err
+	}
+
+	c, err := contact.Unmarshal(udContact)
+	if err != nil {
+		return err
+	}
+
+	var idList []*id.ID
+	err = json.Unmarshal(lookupIds, &idList)
+	if err != nil {
+		return err
+	}
+
+	var p single.RequestParams
+	err = json.Unmarshal(singleRequestParamsJSON, &p)
+	if err != nil {
+		return err
+	}
+
+	respCh := make(chan lookupResp, len(idList))
+	for _, uid := range idList {
+		localID := uid.DeepCopy()
+		callback := func(c contact.Contact, err error) {
+			respCh <- lookupResp{
+				id:      localID,
+				contact: c,
+				err:     err,
+			}
+		}
+		go func() {
+			_, _, err := ud.Lookup(user.api, c, callback, localID, p)
+			if err != nil {
+				respCh <- lookupResp{
+					id:      localID,
+					contact: contact.Contact{},
+					err:     err,
+				}
+			}
+		}()
+
+	}
+
+	go func() {
+		marshaledContactList := make([][]byte, 0)
+		var failedIDs []*id.ID
+		var errorString string
+		for numReturned := 0; numReturned < len(idList); numReturned++ {
+			response := <-respCh
+			if response.err != nil {
+				failedIDs = append(failedIDs, response.id)
+				marshaledContactList = append(
+					marshaledContactList, response.contact.Marshal())
+			} else {
+				errorString = errorString +
+					fmt.Sprintf("Failed to lookup id %s: %+v",
+						response.id, response.err)
+			}
+		}
+
+		marshalledFailedIds, err := json.Marshal(failedIDs)
+		if err != nil {
+			cb.Callback(nil, nil,
+				errors.WithMessage(err,
+					"Failed to marshal failed IDs"))
+		}
+
+		contactListJSON, err := json.Marshal(marshaledContactList)
+		if err != nil {
+			jww.FATAL.Panicf(
+				"Failed to marshal list of contact.Contact: %+v", err)
+		}
+		cb.Callback(contactListJSON, marshalledFailedIds, errors.New(errorString))
+	}()
+
+	return nil
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // User Discovery Search                                                      //
 ////////////////////////////////////////////////////////////////////////////////
@@ -369,8 +558,15 @@ func LookupUD(e2eID int, udContact []byte, cb UdLookupCallback,
 //
 // Parameters:
 //  - contactListJSON - the JSON marshalled bytes of []contact.Contact, or nil
-//    if an error occurs
-//  - err - any errors that occurred in the search
+//    if an error occurs.
+//
+//   JSON Example:
+//   {
+//  	"<xxc(2)F8dL9EC6gy+RMJuk3R+Au6eGExo02Wfio5cacjBcJRwDEgB7Ugdw/BAr6RkCABkWAFV1c2VybmFtZTA7c4LzV05sG+DMt+rFB0NIJg==xxc>",
+//  	"<xxc(2)eMhAi/pYkW5jCmvKE5ZaTglQb+fTo1D8NxVitr5CCFADEgB7Ugdw/BAr6RoCABkWAFV1c2VybmFtZTE7fElAa7z3IcrYrrkwNjMS2w==xxc>",
+//  	"<xxc(2)d7RJTu61Vy1lDThDMn8rYIiKSe1uXA/RCvvcIhq5Yg4DEgB7Ugdw/BAr6RsCABkWAFV1c2VybmFtZTI7N3XWrxIUpR29atpFMkcR6A==xxc>"
+//	}
+//  - err - any errors that occurred in the search.
 type UdSearchCallback interface {
 	Callback(contactListJSON []byte, err error)
 }
@@ -385,14 +581,15 @@ type UdSearchCallback interface {
 //  - e2eID - e2e object ID in the tracker
 //  - udContact - the marshalled bytes of the contact.Contact for the user
 //    discovery server
-//  - factListJSON - the JSON marshalled bytes of fact.FactList
+//  - factListJSON - the JSON marshalled bytes of [fact.FactList]
 //  - singleRequestParams - the JSON marshalled bytes of single.RequestParams
 //
 // Returns:
 //  - []byte - the JSON marshalled bytes of the SingleUseSendReport object,
-//    which can be passed into WaitForRoundResult to see if the send succeeded.
+//    which can be passed into Cmix.WaitForRoundResult to see if the send
+//    operation succeeded.
 func SearchUD(e2eID int, udContact []byte, cb UdSearchCallback,
-	factListJSON []byte, singleRequestParamsJSON []byte) ([]byte, error) {
+	factListJSON, singleRequestParamsJSON []byte) ([]byte, error) {
 
 	// Get user from singleton
 	user, err := e2eTrackerSingleton.get(e2eID)
@@ -418,7 +615,20 @@ func SearchUD(e2eID int, udContact []byte, cb UdSearchCallback,
 	}
 
 	callback := func(contactList []contact.Contact, err error) {
-		contactListJSON, err2 := json.Marshal(contactList)
+		marshaledContactList := make([][]byte, 0)
+		// fixme: it may be wiser to change this callback interface
+		//   to simply do the work below when parsing the response from UD.
+		//   that would change ud/search.go in two places:
+		//    - searchCallback
+		//    - parseContacts
+		//  I avoid doing that as it changes interfaces w/o approval
+		for i := range contactList {
+			con := contactList[i]
+			marshaledContactList = append(
+				marshaledContactList, con.Marshal())
+		}
+
+		contactListJSON, err2 := json.Marshal(marshaledContactList)
 		if err2 != nil {
 			jww.FATAL.Panicf(
 				"Failed to marshal list of contact.Contact: %+v", err2)
@@ -434,8 +644,9 @@ func SearchUD(e2eID int, udContact []byte, cb UdSearchCallback,
 
 	sr := SingleUseSendReport{
 		EphID:       eid.EphId.Int64(),
-		ReceptionID: eid.Source.Marshal(),
+		ReceptionID: eid.Source,
 		RoundsList:  makeRoundsList(rids...),
+		RoundURL:    getRoundURL(rids[0]),
 	}
 
 	return json.Marshal(sr)
diff --git a/bindings/version.go b/bindings/version.go
index e0571df8f1f22855f504b021fe869111781f724b..1dae09cc111915e2b0556d386f041f73c7dc9b62 100644
--- a/bindings/version.go
+++ b/bindings/version.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 // version.go contains functions to report the client version.
 
diff --git a/broadcast/asymmetric.go b/broadcast/asymmetric.go
deleted file mode 100644
index 2b263cad705cadcfd0f9fb5a819a1c019cb8bb4b..0000000000000000000000000000000000000000
--- a/broadcast/asymmetric.go
+++ /dev/null
@@ -1,74 +0,0 @@
-////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
-//                                                                            //
-// Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
-////////////////////////////////////////////////////////////////////////////////
-
-package broadcast
-
-import (
-	"encoding/binary"
-	"github.com/pkg/errors"
-	"gitlab.com/elixxir/client/cmix"
-	"gitlab.com/elixxir/client/cmix/message"
-	"gitlab.com/xx_network/crypto/multicastRSA"
-	"gitlab.com/xx_network/primitives/id"
-	"gitlab.com/xx_network/primitives/id/ephemeral"
-)
-
-const (
-	asymmetricBroadcastServiceTag = "AsymmBcast"
-	asymmCMixSendTag              = "AsymmetricBroadcast"
-	internalPayloadSizeLength     = 2
-)
-
-// BroadcastAsymmetric broadcasts the payload to the channel. Requires a healthy network state to send
-// Payload must be equal to bc.MaxAsymmetricPayloadSize, and the channel PrivateKey must be passed in
-func (bc *broadcastClient) BroadcastAsymmetric(pk multicastRSA.PrivateKey, payload []byte, cMixParams cmix.CMIXParams) (
-	id.Round, ephemeral.Id, error) {
-	// Confirm network health
-	if !bc.net.IsHealthy() {
-		return 0, ephemeral.Id{}, errors.New(errNetworkHealth)
-	}
-
-	// Check payload size
-	if len(payload) > bc.MaxAsymmetricPayloadSize() {
-		return 0, ephemeral.Id{},
-			errors.Errorf(errPayloadSize, len(payload), bc.MaxAsymmetricPayloadSize())
-	}
-	payloadLength := uint16(len(payload))
-
-	finalPayload := make([]byte, bc.maxAsymmetricPayloadSizeRaw())
-	binary.BigEndian.PutUint16(finalPayload[:internalPayloadSizeLength], payloadLength)
-	copy(finalPayload[internalPayloadSizeLength:], payload)
-
-	// Encrypt payload
-	encryptedPayload, mac, fp, err := bc.channel.EncryptAsymmetric(finalPayload, pk, bc.rng.GetStream())
-	if err != nil {
-		return 0, ephemeral.Id{}, errors.WithMessage(err, "Failed to encrypt asymmetric broadcast message")
-	}
-
-	// Create service using asymmetric broadcast service tag & channel reception ID
-	// Allows anybody with this info to listen for messages on this channel
-	service := message.Service{
-		Identifier: bc.channel.ReceptionID.Bytes(),
-		Tag:        asymmetricBroadcastServiceTag,
-	}
-
-	if cMixParams.DebugTag == cmix.DefaultDebugTag {
-		cMixParams.DebugTag = asymmCMixSendTag
-	}
-
-	// Create payload sized for sending over cmix
-	sizedPayload := make([]byte, bc.net.GetMaxMessageLength())
-	// Read random data into sized payload
-	_, err = bc.rng.GetStream().Read(sizedPayload)
-	if err != nil {
-		return 0, ephemeral.Id{}, errors.WithMessage(err, "Failed to add random data to sized broadcast")
-	}
-	copy(sizedPayload[:len(encryptedPayload)], encryptedPayload)
-
-	return bc.net.Send(
-		bc.channel.ReceptionID, fp, service, sizedPayload, mac, cMixParams)
-}
diff --git a/broadcast/broadcastClient.go b/broadcast/client.go
similarity index 53%
rename from broadcast/broadcastClient.go
rename to broadcast/client.go
index 6e1c7391cc6f97ed429cfd4164508444ac3eb0b3..1b4891a00bdf4d8ae9ce6bf31c2b020b356fa114 100644
--- a/broadcast/broadcastClient.go
+++ b/broadcast/client.go
@@ -1,8 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package broadcast
@@ -14,25 +14,30 @@ import (
 	"gitlab.com/elixxir/client/cmix/message"
 	crypto "gitlab.com/elixxir/crypto/broadcast"
 	"gitlab.com/elixxir/crypto/fastRNG"
-	"gitlab.com/xx_network/crypto/signature/rsa"
 )
 
-// broadcastClient implements the Channel interface for sending/receiving asymmetric or symmetric broadcast messages
+// broadcastClient implements the [broadcast.Channel] interface for sending/
+// receiving asymmetric or symmetric broadcast messages.
 type broadcastClient struct {
-	channel crypto.Channel
+	channel *crypto.Channel
 	net     Client
 	rng     *fastRNG.StreamGenerator
 }
 
-// NewBroadcastChannel creates a channel interface based on crypto.Channel, accepts net client connection & callback for received messages
-func NewBroadcastChannel(channel crypto.Channel, net Client, rng *fastRNG.StreamGenerator) (Channel, error) {
+type NewBroadcastChannelFunc func(channel *crypto.Channel, net Client,
+	rng *fastRNG.StreamGenerator) (Channel, error)
+
+// NewBroadcastChannel creates a channel interface based on [broadcast.Channel].
+// It accepts a Cmix client connection.
+func NewBroadcastChannel(channel *crypto.Channel, net Client,
+	rng *fastRNG.StreamGenerator) (Channel, error) {
 	bc := &broadcastClient{
 		channel: channel,
 		net:     net,
 		rng:     rng,
 	}
 
-	if !bc.verifyID() {
+	if !channel.Verify() {
 		return nil, errors.New("Failed ID verification for broadcast channel")
 	}
 
@@ -45,20 +50,21 @@ func NewBroadcastChannel(channel crypto.Channel, net Client, rng *fastRNG.Stream
 	return bc, nil
 }
 
-// RegisterListener adds a service to hear broadcast messages of a given type via the passed in callback
+// RegisterListener registers a listener for broadcast messages.
 func (bc *broadcastClient) RegisterListener(listenerCb ListenerFunc, method Method) error {
 	var tag string
 	switch method {
 	case Symmetric:
 		tag = symmetricBroadcastServiceTag
-	case Asymmetric:
-		tag = asymmetricBroadcastServiceTag
+	case RSAToPublic:
+		tag = asymmetricRSAToPublicBroadcastServiceTag
 	default:
-		return errors.Errorf("Cannot register listener for broadcast method %s", method)
+		return errors.Errorf(
+			"Cannot register listener for broadcast method %s", method)
 	}
 
 	p := &processor{
-		c:      &bc.channel,
+		c:      bc.channel,
 		cb:     listenerCb,
 		method: method,
 	}
@@ -72,8 +78,8 @@ func (bc *broadcastClient) RegisterListener(listenerCb ListenerFunc, method Meth
 	return nil
 }
 
-// Stop unregisters the listener callback and stops the channel's identity
-// from being tracked.
+// Stop unregisters the listener callback and stops the channel's identity from
+// being tracked.
 func (bc *broadcastClient) Stop() {
 	// Removes currently tracked identity
 	bc.net.RemoveIdentity(bc.channel.ReceptionID)
@@ -82,29 +88,27 @@ func (bc *broadcastClient) Stop() {
 	bc.net.DeleteClientService(bc.channel.ReceptionID)
 }
 
-// Get returns the underlying crypto.Channel object
-func (bc *broadcastClient) Get() crypto.Channel {
+// Get returns the underlying [broadcast.Channel] object.
+func (bc *broadcastClient) Get() *crypto.Channel {
 	return bc.channel
 }
 
-// verifyID generates a symmetric ID based on the info in the channel & compares it to the one passed in
-func (bc *broadcastClient) verifyID() bool {
-	gen, err := crypto.NewChannelID(bc.channel.Name, bc.channel.Description, bc.channel.Salt, rsa.CreatePublicKeyPem(bc.channel.RsaPubKey))
-	if err != nil {
-		jww.FATAL.Panicf("[verifyID] Failed to generate verified channel ID")
-		return false
-	}
-	return bc.channel.ReceptionID.Cmp(gen)
-}
-
+// MaxPayloadSize returns the maximum size for a symmetric broadcast payload.
 func (bc *broadcastClient) MaxPayloadSize() int {
 	return bc.maxSymmetricPayload()
 }
 
-func (bc *broadcastClient) MaxAsymmetricPayloadSize() int {
-	return bc.maxAsymmetricPayloadSizeRaw() - internalPayloadSizeLength
+func (bc *broadcastClient) maxSymmetricPayload() int {
+	return bc.channel.GetMaxSymmetricPayloadSize(bc.net.GetMaxMessageLength())
+}
+
+// MaxRSAToPublicPayloadSize return the maximum payload size for a
+// [broadcast.RSAToPublic] asymmetric payload.
+func (bc *broadcastClient) MaxRSAToPublicPayloadSize() int {
+	return bc.maxRSAToPublicPayloadSizeRaw() - internalPayloadSizeLength
 }
 
-func (bc *broadcastClient) maxAsymmetricPayloadSizeRaw() int {
-	return bc.channel.MaxAsymmetricPayloadSize()
+func (bc *broadcastClient) maxRSAToPublicPayloadSizeRaw() int {
+	size, _, _ := bc.channel.GetRSAToPublicMessageLength()
+	return size
 }
diff --git a/broadcast/interface.go b/broadcast/interface.go
index bd464945549ba67b4800dcef5c1f4f9d339d061d..3c674c0db3438862296e8980afcb8177eb3d2a9a 100644
--- a/broadcast/interface.go
+++ b/broadcast/interface.go
@@ -1,8 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package broadcast
@@ -13,40 +13,69 @@ import (
 	"gitlab.com/elixxir/client/cmix/message"
 	"gitlab.com/elixxir/client/cmix/rounds"
 	crypto "gitlab.com/elixxir/crypto/broadcast"
-	"gitlab.com/elixxir/primitives/format"
-	"gitlab.com/xx_network/crypto/multicastRSA"
+	"gitlab.com/elixxir/crypto/rsa"
 	"gitlab.com/xx_network/primitives/id"
 	"gitlab.com/xx_network/primitives/id/ephemeral"
 	"time"
 )
 
-// ListenerFunc is registered when creating a new broadcasting channel
-// and receives all new broadcast messages for the channel.
+// ListenerFunc is registered when creating a new broadcasting channel and
+// receives all new broadcast messages for the channel.
 type ListenerFunc func(payload []byte,
 	receptionID receptionID.EphemeralIdentity, round rounds.Round)
 
-// Channel is the public-facing interface to interact with broadcast channels
+// Channel is the public-facing interface to interact with broadcast channels.
 type Channel interface {
-	// MaxPayloadSize returns the maximum size for a symmetric broadcast payload
+	// MaxPayloadSize returns the maximum size for a symmetric broadcast
+	// payload.
 	MaxPayloadSize() int
 
-	// MaxAsymmetricPayloadSize returns the maximum size for an asymmetric broadcast payload
-	MaxAsymmetricPayloadSize() int
+	// MaxRSAToPublicPayloadSize returns the maximum size for an asymmetric
+	// broadcast payload.
+	MaxRSAToPublicPayloadSize() int
 
-	// Get returns the underlying crypto.Channel
-	Get() crypto.Channel
+	// Get returns the underlying [broadcast.Channel] object.
+	Get() *crypto.Channel
 
-	// Broadcast broadcasts the payload to the channel. The payload size must be
-	// equal to MaxPayloadSize.
+	// Broadcast broadcasts a payload to the channel. The payload must be of the
+	// size [Channel.MaxPayloadSize] or smaller.
+	//
+	// The network must be healthy to send.
 	Broadcast(payload []byte, cMixParams cmix.CMIXParams) (
-		id.Round, ephemeral.Id, error)
+		rounds.Round, ephemeral.Id, error)
 
-	// BroadcastAsymmetric broadcasts an asymmetric payload to the channel. The payload size must be
-	// equal to MaxPayloadSize & private key for channel must be passed in
-	BroadcastAsymmetric(pk multicastRSA.PrivateKey, payload []byte, cMixParams cmix.CMIXParams) (
-		id.Round, ephemeral.Id, error)
+	// BroadcastWithAssembler broadcasts a payload over a channel with a payload
+	// assembled after the round is selected, allowing the round info to be
+	// included in the payload.
+	//
+	// The payload must be of the size [Channel.MaxPayloadSize] or smaller.
+	//
+	// The network must be healthy to send.
+	BroadcastWithAssembler(assembler Assembler, cMixParams cmix.CMIXParams) (
+		rounds.Round, ephemeral.Id, error)
 
-	// RegisterListener registers a listener for broadcast messages
+	// BroadcastRSAtoPublic broadcasts the payload to the channel.
+	//
+	// The payload must be of the size [Channel.MaxRSAToPublicPayloadSize] or
+	// smaller and the channel [rsa.PrivateKey] must be passed in.
+	//
+	// The network must be healthy to send.
+	BroadcastRSAtoPublic(pk rsa.PrivateKey, payload []byte,
+		cMixParams cmix.CMIXParams) (rounds.Round, ephemeral.Id, error)
+
+	// BroadcastRSAToPublicWithAssembler broadcasts the payload to the channel
+	// with a function that builds the payload based upon the ID of the selected
+	// round.
+	//
+	// The payload must be of the size [Channel.MaxRSAToPublicPayloadSize] or
+	// smaller and the channel [rsa.PrivateKey] must be passed in.
+	//
+	// The network must be healthy to send.
+	BroadcastRSAToPublicWithAssembler(
+		pk rsa.PrivateKey, assembler Assembler,
+		cMixParams cmix.CMIXParams) (rounds.Round, ephemeral.Id, error)
+
+	// RegisterListener registers a listener for broadcast messages.
 	RegisterListener(listenerCb ListenerFunc, method Method) error
 
 	// Stop unregisters the listener callback and stops the channel's identity
@@ -54,17 +83,19 @@ type Channel interface {
 	Stop()
 }
 
-// Client contains the methods from cmix.Client that are required by
-// symmetricClient.
+// Assembler is a function which allows a bre
+type Assembler func(rid id.Round) (payload []byte, err error)
+
+// Client contains the methods from [cmix.Client] that are required by
+// broadcastClient.
 type Client interface {
-	GetMaxMessageLength() int
-	Send(recipient *id.ID, fingerprint format.Fingerprint,
-		service message.Service, payload, mac []byte,
-		cMixParams cmix.CMIXParams) (id.Round, ephemeral.Id, error)
+	SendWithAssembler(recipient *id.ID, assembler cmix.MessageAssembler,
+		cmixParams cmix.CMIXParams) (rounds.Round, ephemeral.Id, error)
 	IsHealthy() bool
 	AddIdentity(id *id.ID, validUntil time.Time, persistent bool)
 	AddService(clientID *id.ID, newService message.Service,
 		response message.Processor)
 	DeleteClientService(clientID *id.ID)
 	RemoveIdentity(id *id.ID)
+	GetMaxMessageLength() int
 }
diff --git a/broadcast/method.go b/broadcast/method.go
index e493151504b00fabf320429b5da52a474f23efed..c154fc027b81a55f600c5f54fa3847aa7616ea89 100644
--- a/broadcast/method.go
+++ b/broadcast/method.go
@@ -1,8 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package broadcast
@@ -12,15 +12,18 @@ type Method uint8
 
 const (
 	Symmetric Method = iota
-	Asymmetric
+	RSAToPublic
+	RSAToPrivate
 )
 
 func (m Method) String() string {
 	switch m {
 	case Symmetric:
 		return "Symmetric"
-	case Asymmetric:
-		return "Asymmetric"
+	case RSAToPublic:
+		return "RSAToPublic"
+	case RSAToPrivate:
+		return "RSAToPrivate"
 	default:
 		return "Unknown"
 	}
diff --git a/broadcast/processor.go b/broadcast/processor.go
index 651974c4cb648aba5df3e56fa8f46901cc1a2899..8ee1f85d07ad093337711ef15e7f6e3ced3dd1f8 100644
--- a/broadcast/processor.go
+++ b/broadcast/processor.go
@@ -1,8 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package broadcast
@@ -35,10 +35,8 @@ func (p *processor) Process(msg format.Message,
 	var payload []byte
 	var err error
 	switch p.method {
-	case Asymmetric:
-		encPartSize := p.c.RsaPubKey.Size()               // Size returned by multicast RSA encryption
-		encodedMessage := msg.GetContents()[:encPartSize] // Only one message is encoded, rest of it is random data
-		decodedMessage, decryptErr := p.c.DecryptAsymmetric(encodedMessage)
+	case RSAToPublic:
+		decodedMessage, decryptErr := p.c.DecryptRSAToPublic(msg.GetContents(), msg.GetMac(), msg.GetKeyFP())
 		if decryptErr != nil {
 			jww.ERROR.Printf(errDecrypt, p.c.ReceptionID, p.c.Name, decryptErr)
 			return
@@ -53,10 +51,10 @@ func (p *processor) Process(msg format.Message,
 			return
 		}
 	default:
-		jww.ERROR.Printf("Unrecognized broadcast method %d", p.method)
+		jww.FATAL.Panicf("Unrecognized broadcast method %d", p.method)
 	}
 
-	go p.cb(payload, receptionID, round)
+	p.cb(payload, receptionID, round)
 }
 
 // String returns a string identifying the symmetricProcessor for debugging purposes.
diff --git a/broadcast/processor_test.go b/broadcast/processor_test.go
index 9e48f372e92663eea061a8a7d72e0fbe13d58eee..b758c20dbfa8756a31cc554671ab884d6b312a56 100644
--- a/broadcast/processor_test.go
+++ b/broadcast/processor_test.go
@@ -1,26 +1,13 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package broadcast
 
-import (
-	"bytes"
-	"gitlab.com/elixxir/client/cmix/identity/receptionID"
-	"gitlab.com/elixxir/client/cmix/rounds"
-	crypto "gitlab.com/elixxir/crypto/broadcast"
-	"gitlab.com/elixxir/crypto/cmix"
-	"gitlab.com/elixxir/primitives/format"
-	"gitlab.com/xx_network/crypto/csprng"
-	"gitlab.com/xx_network/crypto/signature/rsa"
-	"gitlab.com/xx_network/primitives/id"
-	"testing"
-	"time"
-)
-
+/*
 // Tests that process.Process properly decrypts the payload and passes it to the
 // callback.
 func Test_processor_Process(t *testing.T) {
@@ -37,7 +24,7 @@ func Test_processor_Process(t *testing.T) {
 		RsaPubKey:   rsaPrivKey.GetPublic(),
 	}
 
-	cbChan := make(chan []byte)
+	cbChan := make(chan []byte, 1)
 	cb := func(payload []byte, _ receptionID.EphemeralIdentity, _ rounds.Round) {
 		cbChan <- payload
 	}
@@ -67,4 +54,4 @@ func Test_processor_Process(t *testing.T) {
 	case <-time.After(15 * time.Millisecond):
 		t.Error("Timed out waiting for listener channel to be called.")
 	}
-}
+}*/
diff --git a/broadcast/rsaToPublic.go b/broadcast/rsaToPublic.go
new file mode 100644
index 0000000000000000000000000000000000000000..26c4d0924af04c6464610f20fe8040ac1aa7b082
--- /dev/null
+++ b/broadcast/rsaToPublic.go
@@ -0,0 +1,121 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
+package broadcast
+
+import (
+	"encoding/binary"
+	"github.com/pkg/errors"
+	"gitlab.com/elixxir/client/cmix"
+	"gitlab.com/elixxir/client/cmix/message"
+	"gitlab.com/elixxir/client/cmix/rounds"
+	"gitlab.com/elixxir/crypto/rsa"
+	"gitlab.com/elixxir/primitives/format"
+	"gitlab.com/xx_network/primitives/id"
+	"gitlab.com/xx_network/primitives/id/ephemeral"
+)
+
+const (
+	asymmetricRSAToPublicBroadcastServiceTag = "AsymmToPublicBcast"
+	asymmCMixSendTag                         = "AsymmetricBroadcast"
+	internalPayloadSizeLength                = 2
+)
+
+// BroadcastRSAtoPublic broadcasts the payload to the channel. Requires a
+// healthy network state to send Payload length less than or equal to
+// bc.MaxRSAToPublicPayloadSize, and the channel PrivateKey must be passed in
+//
+// BroadcastRSAtoPublic broadcasts the payload to the channel.
+//
+// The payload must be of the size [broadcastClient.MaxRSAToPublicPayloadSize]
+// or smaller and the channel [rsa.PrivateKey] must be passed in.
+//
+// The network must be healthy to send.
+func (bc *broadcastClient) BroadcastRSAtoPublic(pk rsa.PrivateKey,
+	payload []byte, cMixParams cmix.CMIXParams) (rounds.Round, ephemeral.Id, error) {
+	// Confirm network health
+
+	assemble := func(rid id.Round) ([]byte, error) {
+		return payload, nil
+	}
+	return bc.BroadcastRSAToPublicWithAssembler(pk, assemble, cMixParams)
+}
+
+// BroadcastRSAToPublicWithAssembler broadcasts the payload to the channel
+// with a function that builds the payload based upon the ID of the selected
+// round.
+//
+// The payload must be of the size [broadcastClient.MaxRSAToPublicPayloadSize]
+// or smaller and the channel [rsa.PrivateKey] must be passed in.
+//
+// The network must be healthy to send.
+func (bc *broadcastClient) BroadcastRSAToPublicWithAssembler(
+	pk rsa.PrivateKey, assembler Assembler,
+	cMixParams cmix.CMIXParams) (rounds.Round, ephemeral.Id, error) {
+	// Confirm network health
+	if !bc.net.IsHealthy() {
+		return rounds.Round{}, ephemeral.Id{}, errors.New(errNetworkHealth)
+	}
+
+	assemble := func(rid id.Round) (fp format.Fingerprint,
+		service message.Service, encryptedPayload, mac []byte, err error) {
+		payload, err := assembler(rid)
+		if err != nil {
+			return format.Fingerprint{}, message.Service{}, nil,
+				nil, err
+		}
+		// Check payload size
+		if len(payload) > bc.MaxRSAToPublicPayloadSize() {
+			return format.Fingerprint{}, message.Service{}, nil,
+				nil, errors.Errorf(errPayloadSize, len(payload),
+					bc.MaxRSAToPublicPayloadSize())
+		}
+		payloadLength := uint16(len(payload))
+
+		finalPayload := make([]byte, bc.maxRSAToPublicPayloadSizeRaw())
+		binary.BigEndian.PutUint16(finalPayload[:internalPayloadSizeLength],
+			payloadLength)
+		copy(finalPayload[internalPayloadSizeLength:], payload)
+
+		// Encrypt payload
+		encryptedPayload, mac, fp, err =
+			bc.channel.EncryptRSAToPublic(finalPayload, pk, bc.net.GetMaxMessageLength(),
+				bc.rng.GetStream())
+		if err != nil {
+			return format.Fingerprint{}, message.Service{}, nil,
+				nil, errors.WithMessage(err, "Failed to encrypt "+
+					"asymmetric broadcast message")
+		}
+
+		// Create service using asymmetric broadcast service tag & channel
+		// reception ID allows anybody with this info to listen for messages on
+		// this channel
+		service = message.Service{
+			Identifier: bc.channel.ReceptionID.Bytes(),
+			Tag:        asymmetricRSAToPublicBroadcastServiceTag,
+		}
+
+		if cMixParams.DebugTag == cmix.DefaultDebugTag {
+			cMixParams.DebugTag = asymmCMixSendTag
+		}
+
+		// Create payload sized for sending over cmix
+		sizedPayload := make([]byte, bc.net.GetMaxMessageLength())
+		// Read random data into sized payload
+		_, err = bc.rng.GetStream().Read(sizedPayload)
+		if err != nil {
+			return format.Fingerprint{}, message.Service{}, nil,
+				nil, errors.WithMessage(err, "Failed to add "+
+					"random data to sized broadcast")
+		}
+		copy(sizedPayload[:len(encryptedPayload)], encryptedPayload)
+
+		return
+	}
+
+	return bc.net.SendWithAssembler(bc.channel.ReceptionID, assemble, cMixParams)
+}
diff --git a/broadcast/asymmetric_test.go b/broadcast/rsaToPublic_test.go
similarity index 51%
rename from broadcast/asymmetric_test.go
rename to broadcast/rsaToPublic_test.go
index 776879127b040946b8147c184341cc4860de3296..159f9d1016ead09866c8db1bd3f15faedfc94404 100644
--- a/broadcast/asymmetric_test.go
+++ b/broadcast/rsaToPublic_test.go
@@ -1,58 +1,80 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package broadcast
 
 import (
 	"bytes"
 	"fmt"
+	"reflect"
+	"sync"
+	"testing"
+	"time"
+
+	"gitlab.com/xx_network/crypto/csprng"
+
 	"gitlab.com/elixxir/client/cmix"
 	"gitlab.com/elixxir/client/cmix/identity/receptionID"
+	"gitlab.com/elixxir/client/cmix/message"
 	"gitlab.com/elixxir/client/cmix/rounds"
 	crypto "gitlab.com/elixxir/crypto/broadcast"
-	cMixCrypto "gitlab.com/elixxir/crypto/cmix"
 	"gitlab.com/elixxir/crypto/fastRNG"
-	"gitlab.com/xx_network/crypto/csprng"
-	"gitlab.com/xx_network/crypto/signature/rsa"
-	"reflect"
-	"sync"
-	"testing"
-	"time"
+	"gitlab.com/elixxir/primitives/format"
 )
 
-// Tests that symmetricClient adheres to the Symmetric interface.
+// Tests that broadcastClient adheres to the Channel interface.
 var _ Channel = (*broadcastClient)(nil)
 
-// Tests that symmetricClient adheres to the Symmetric interface.
+// Tests that cmix.Client adheres to the Client interface.
 var _ Client = (cmix.Client)(nil)
 
+// Tests that mockProcessor adheres to the message.Processor interface.
+var _ message.Processor = (*mockProcessor)(nil)
+
+// mockProcessor adheres to the message.Processor interface.
+type mockProcessor struct {
+	messages []format.Message
+}
+
+func newMockProcessor() *mockProcessor {
+	m := new(mockProcessor)
+	m.messages = make([]format.Message, 0)
+	return m
+}
+func (p *mockProcessor) Process(message format.Message,
+	_ receptionID.EphemeralIdentity, _ rounds.Round) {
+	p.messages = append(p.messages, message)
+}
+func (p *mockProcessor) String() string { return "hello" }
+
 func Test_asymmetricClient_Smoke(t *testing.T) {
 	cMixHandler := newMockCmixHandler()
 	rngGen := fastRNG.NewStreamGenerator(1000, 10, csprng.NewSystemRNG)
-	pk, err := rsa.GenerateKey(rngGen.GetStream(), 4096)
-	if err != nil {
-		t.Fatalf("Failed to generate priv key: %+v", err)
-	}
-	cname := "MyChannel"
-	cdesc := "This is my channel about stuff."
-	csalt := cMixCrypto.NewSalt(csprng.NewSystemRNG(), 32)
-	cpubkey := pk.GetPublic()
-	cid, err := crypto.NewChannelID(cname, cdesc, csalt, rsa.CreatePublicKeyPem(cpubkey))
-	if err != nil {
-		t.Errorf("Failed to create channel ID: %+v", err)
-	}
-	channel := crypto.Channel{
-		ReceptionID: cid,
-		Name:        cname,
-		Description: cdesc,
-		Salt:        csalt,
-		RsaPubKey:   cpubkey,
-	}
+	cName := "MyChannel"
+	cDesc := "This is my channel about stuff."
+	packetPayloadLength := newMockCmix(cMixHandler).GetMaxMessageLength()
+
+	channel, pk, _ := crypto.NewChannel(
+		cName, cDesc, packetPayloadLength, rngGen.GetStream())
+	cid := channel.ReceptionID
+
+	// Must mutate cMixHandler such that it's processorMap contains a
+	// message.Processor
+	mockProc := newMockProcessor()
+	cMixHandler.processorMap[*cid] = make(map[string][]message.Processor)
+	cMixHandler.processorMap[*cid]["AsymmBcast"] = []message.Processor{mockProc}
 
-	const n = 5
+	const n = 1
 	cbChans := make([]chan []byte, n)
 	clients := make([]Channel, n)
 	for i := range clients {
 		cbChan := make(chan []byte, 10)
-		cb := func(payload []byte, _ receptionID.EphemeralIdentity,
-			_ rounds.Round) {
+		cb := func(
+			payload []byte, _ receptionID.EphemeralIdentity, _ rounds.Round) {
 			cbChan <- payload
 		}
 
@@ -61,7 +83,7 @@ func Test_asymmetricClient_Smoke(t *testing.T) {
 			t.Errorf("Failed to create broadcast channel: %+v", err)
 		}
 
-		err = s.RegisterListener(cb, Asymmetric)
+		err = s.RegisterListener(cb, RSAToPublic)
 		if err != nil {
 			t.Errorf("Failed to register listener: %+v", err)
 		}
@@ -69,7 +91,7 @@ func Test_asymmetricClient_Smoke(t *testing.T) {
 		cbChans[i] = cbChan
 		clients[i] = s
 
-		// Test that Get returns the expected channel
+		// Test that Channel.Get returns the expected channel
 		if !reflect.DeepEqual(s.Get(), channel) {
 			t.Errorf("Cmix %d returned wrong channel."+
 				"\nexpected: %+v\nreceived: %+v", i, channel, s.Get())
@@ -78,7 +100,7 @@ func Test_asymmetricClient_Smoke(t *testing.T) {
 
 	// Send broadcast from each client
 	for i := range clients {
-		payload := make([]byte, clients[i].MaxAsymmetricPayloadSize())
+		payload := make([]byte, clients[i].MaxRSAToPublicPayloadSize())
 		copy(payload,
 			fmt.Sprintf("Hello from client %d of %d.", i, len(clients)))
 
@@ -91,9 +113,9 @@ func Test_asymmetricClient_Smoke(t *testing.T) {
 				select {
 				case r := <-cbChan:
 					if !bytes.Equal(payload, r) {
-						t.Errorf("Cmix %d failed to receive expected "+
-							"payload from client %d."+
-							"\nexpected: %q\nreceived: %q", j, i, payload, r)
+						t.Errorf("Cmix %d failed to receive expected payload "+
+							"from client %d.\nexpected: %q\nreceived: %q",
+							j, i, payload, r)
 					}
 				case <-time.After(time.Second):
 					t.Errorf("Cmix %d timed out waiting for broadcast "+
@@ -103,7 +125,8 @@ func Test_asymmetricClient_Smoke(t *testing.T) {
 		}
 
 		// Broadcast payload
-		_, _, err := clients[i].BroadcastAsymmetric(pk, payload, cmix.GetDefaultCMIXParams())
+		_, _, err := clients[i].BroadcastRSAtoPublic(
+			pk, payload, cmix.GetDefaultCMIXParams())
 		if err != nil {
 			t.Errorf("Cmix %d failed to send broadcast: %+v", i, err)
 		}
@@ -117,7 +140,7 @@ func Test_asymmetricClient_Smoke(t *testing.T) {
 		clients[i].Stop()
 	}
 
-	payload := make([]byte, clients[0].MaxAsymmetricPayloadSize())
+	payload := make([]byte, clients[0].MaxRSAToPublicPayloadSize())
 	copy(payload, "This message should not get through.")
 
 	// Start waiting on channels and error if anything is received
@@ -135,7 +158,7 @@ func Test_asymmetricClient_Smoke(t *testing.T) {
 	}
 
 	// Broadcast payload
-	_, _, err = clients[0].BroadcastAsymmetric(pk, payload, cmix.GetDefaultCMIXParams())
+	_, _, err := clients[0].BroadcastRSAtoPublic(pk, payload, cmix.GetDefaultCMIXParams())
 	if err != nil {
 		t.Errorf("Cmix 0 failed to send broadcast: %+v", err)
 	}
diff --git a/broadcast/sizedBroadcast.go b/broadcast/sizedBroadcast.go
deleted file mode 100644
index d05effe1bcf93b07a0f3cd3533c28df8136c3a46..0000000000000000000000000000000000000000
--- a/broadcast/sizedBroadcast.go
+++ /dev/null
@@ -1,83 +0,0 @@
-////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
-//                                                                            //
-// Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
-////////////////////////////////////////////////////////////////////////////////
-
-package broadcast
-
-import (
-	"encoding/binary"
-	"github.com/pkg/errors"
-)
-
-// Message field sizes.
-const (
-	sizeSize              = 2
-	sizedBroadcastMinSize = sizeSize
-)
-
-// Error messages.
-const (
-	// NewSizedBroadcast
-	errNewSizedBroadcastMaxSize = "size of payload and its size %d too large to fit in max payload size %d"
-
-	// DecodeSizedBroadcast
-	errDecodeSizedBroadcastDataLen = "size of data %d must be greater than %d"
-	errDecodeSizedBroadcastSize    = "stated payload size %d larger than provided data %d"
-)
-
-/*
-+---------------------------+
-|   cMix Message Contents   |
-+---------+-----------------+
-|  Size   |     Payload     |
-| 2 bytes | remaining space |
-+---------+-----------------+
-*/
-
-// NewSizedBroadcast creates a new broadcast payload of size maxPayloadSize that
-// contains the given payload so that it fits completely inside a broadcasted
-// cMix message payload. The length of the payload is stored internally and used
-// to strip extraneous padding when decoding the payload.
-// The maxPayloadSize is the maximum size of the resulting payload. Returns an
-// error when the provided payload cannot fit in the max payload size.
-func NewSizedBroadcast(maxPayloadSize int, payload []byte) ([]byte, error) {
-	if len(payload)+sizedBroadcastMinSize > maxPayloadSize {
-		return nil, errors.Errorf(errNewSizedBroadcastMaxSize,
-			len(payload)+sizedBroadcastMinSize, maxPayloadSize)
-	}
-
-	b := make([]byte, sizeSize)
-	binary.LittleEndian.PutUint16(b, uint16(len(payload)))
-
-	sizedPayload := make([]byte, maxPayloadSize)
-	copy(sizedPayload, append(b, payload...))
-
-	return sizedPayload, nil
-}
-
-// DecodeSizedBroadcast decodes the data into its original payload stripping off
-// extraneous padding.
-func DecodeSizedBroadcast(data []byte) ([]byte, error) {
-	if len(data) < sizedBroadcastMinSize {
-		return nil, errors.Errorf(
-			errDecodeSizedBroadcastDataLen, len(data), sizedBroadcastMinSize)
-	}
-
-	size := binary.LittleEndian.Uint16(data[:sizeSize])
-	if int(size) > len(data[sizeSize:]) {
-		return nil, errors.Errorf(
-			errDecodeSizedBroadcastSize, size, len(data[sizeSize:]))
-	}
-
-	return data[sizeSize : size+sizeSize], nil
-}
-
-// MaxSizedBroadcastPayloadSize returns the maximum size of a payload that can
-// fit in a sized broadcast message for the given maximum cMix message payload
-// size.
-func MaxSizedBroadcastPayloadSize(maxPayloadSize int) int {
-	return maxPayloadSize - sizedBroadcastMinSize
-}
diff --git a/broadcast/sizedBroadcast_test.go b/broadcast/sizedBroadcast_test.go
deleted file mode 100644
index a065101498b5bb6fe22ba66804f85190b8aab887..0000000000000000000000000000000000000000
--- a/broadcast/sizedBroadcast_test.go
+++ /dev/null
@@ -1,115 +0,0 @@
-////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
-//                                                                            //
-// Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
-////////////////////////////////////////////////////////////////////////////////
-
-package broadcast
-
-import (
-	"bytes"
-	"fmt"
-	"testing"
-)
-
-// Tests that a payload smaller than the max payload size encoded via
-// NewSizedBroadcast and decoded via DecodeSizedBroadcast matches the original.
-func TestNewSizedBroadcast_DecodeSizedBroadcast_SmallPayload(t *testing.T) {
-	const maxPayloadSize = 512
-	payload := []byte("This is my payload message.")
-
-	data, err := NewSizedBroadcast(maxPayloadSize, payload)
-	if err != nil {
-		t.Errorf("NewSizedBroadcast returned an error: %+v", err)
-	}
-
-	decodedPayload, err := DecodeSizedBroadcast(data)
-	if err != nil {
-		t.Errorf("DecodeSizedBroadcast returned an error: %+v", err)
-	}
-
-	if !bytes.Equal(payload, decodedPayload) {
-		t.Errorf("Decoded payload does not match original."+
-			"\nexpected: %q\nreceived: %q", payload, decodedPayload)
-	}
-}
-
-// Tests that a payload the same size as the max payload size encoded via
-// NewSizedBroadcast and decoded via DecodeSizedBroadcast matches the original.
-func TestNewSizedBroadcast_DecodeSizedBroadcast_FullSizesPayload(t *testing.T) {
-	payload := []byte("This is my payload message.")
-	maxPayloadSize := len(payload) + sizeSize
-
-	data, err := NewSizedBroadcast(maxPayloadSize, payload)
-	if err != nil {
-		t.Errorf("NewSizedBroadcast returned an error: %+v", err)
-	}
-
-	decodedPayload, err := DecodeSizedBroadcast(data)
-	if err != nil {
-		t.Errorf("DecodeSizedBroadcast returned an error: %+v", err)
-	}
-
-	if !bytes.Equal(payload, decodedPayload) {
-		t.Errorf("Decoded payload does not match original."+
-			"\nexpected: %q\nreceived: %q", payload, decodedPayload)
-	}
-}
-
-// Error path: tests that NewSizedBroadcast returns an error when the payload is
-// larger than the max payload size.
-func TestNewSizedBroadcast_MaxPayloadSizeError(t *testing.T) {
-	payload := []byte("This is my payload message.")
-	maxPayloadSize := len(payload)
-	expectedErr := fmt.Sprintf(errNewSizedBroadcastMaxSize,
-		len(payload)+sizedBroadcastMinSize, maxPayloadSize)
-
-	_, err := NewSizedBroadcast(maxPayloadSize, payload)
-	if err == nil || err.Error() != expectedErr {
-		t.Errorf("NewSizedBroadcast did not return the expected error when "+
-			"the payload is too large.\nexpected: %s\nreceived: %+v",
-			expectedErr, err)
-	}
-}
-
-// Error path: tests that DecodeSizedBroadcast returns an error when the length
-// of the data is shorter than the minimum length of a sized broadcast.
-func TestDecodeSizedBroadcast_DataTooShortError(t *testing.T) {
-	data := []byte{0}
-	expectedErr := fmt.Sprintf(
-		errDecodeSizedBroadcastDataLen, len(data), sizedBroadcastMinSize)
-
-	_, err := DecodeSizedBroadcast(data)
-	if err == nil || err.Error() != expectedErr {
-		t.Errorf("DecodeSizedBroadcast did not return the expected error "+
-			"when the data is too small.\nexpected: %s\nreceived: %+v",
-			expectedErr, err)
-	}
-}
-
-// Error path: tests that DecodeSizedBroadcast returns an error when the payload
-// size is larger than the actual payload contained in the data.
-func TestDecodeSizedBroadcast_SizeMismatchError(t *testing.T) {
-	data := []byte{255, 0, 10}
-	expectedErr := fmt.Sprintf(
-		errDecodeSizedBroadcastSize, data[0], len(data[sizeSize:]))
-
-	_, err := DecodeSizedBroadcast(data)
-	if err == nil || err.Error() != expectedErr {
-		t.Errorf("DecodeSizedBroadcast did not return the expected error "+
-			"when the size is too large.\nexpected: %s\nreceived: %+v",
-			expectedErr, err)
-	}
-}
-
-// Tests that MaxSizedBroadcastPayloadSize returns the correct max size.
-func TestMaxSizedBroadcastPayloadSize(t *testing.T) {
-	maxPayloadSize := 512
-	expectedSize := maxPayloadSize - sizedBroadcastMinSize
-	receivedSize := MaxSizedBroadcastPayloadSize(maxPayloadSize)
-	if receivedSize != expectedSize {
-		t.Errorf("Incorrect max paylaod size.\nexpected: %d\nreceived: %d",
-			expectedSize, receivedSize)
-	}
-}
diff --git a/broadcast/symmetric.go b/broadcast/symmetric.go
index 601c2bebec39f7c00c1e389a9f2d0d8ccc5122f3..432c53c8cab2ae80ea16f915d0142136a0d1532d 100644
--- a/broadcast/symmetric.go
+++ b/broadcast/symmetric.go
@@ -1,8 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package broadcast
@@ -11,13 +11,15 @@ import (
 	"github.com/pkg/errors"
 	"gitlab.com/elixxir/client/cmix"
 	"gitlab.com/elixxir/client/cmix/message"
+	"gitlab.com/elixxir/client/cmix/rounds"
+	"gitlab.com/elixxir/primitives/format"
 	"gitlab.com/xx_network/primitives/id"
 	"gitlab.com/xx_network/primitives/id/ephemeral"
 )
 
 // Error messages.
 const (
-	// symmetricClient.Broadcast
+	// broadcastClient.Broadcast
 	errNetworkHealth       = "cannot send broadcast when the network is not healthy"
 	errPayloadSize         = "size of payload %d must be less than %d"
 	errBroadcastMethodType = "cannot call %s broadcast using %s channel"
@@ -29,41 +31,68 @@ const (
 	symmetricBroadcastServiceTag = "SymmetricBroadcast"
 )
 
-// MaxSymmetricPayloadSize returns the maximum size for a broadcasted payload.
-func (bc *broadcastClient) maxSymmetricPayload() int {
-	return bc.net.GetMaxMessageLength()
+// Broadcast broadcasts a payload to a symmetric channel. The payload must be of
+// size [broadcastClient.MaxPayloadSize] or smaller.
+//
+// The network must be healthy to send.
+func (bc *broadcastClient) Broadcast(payload []byte, cMixParams cmix.CMIXParams) (
+	rounds.Round, ephemeral.Id, error) {
+	assemble := func(rid id.Round) ([]byte, error) {
+		return payload, nil
+	}
+	return bc.BroadcastWithAssembler(assemble, cMixParams)
 }
 
-// Broadcast broadcasts a payload over a symmetric channel.
-// Network must be healthy to send
-// Requires a payload of size bc.MaxSymmetricPayloadSize()
-func (bc *broadcastClient) Broadcast(payload []byte, cMixParams cmix.CMIXParams) (
-	id.Round, ephemeral.Id, error) {
+// BroadcastWithAssembler broadcasts a payload over a symmetric channel with a
+// payload assembled after the round is selected, allowing the round info to be
+// included in the payload.
+//
+// The payload must be of the size [Channel.MaxPayloadSize] or smaller.
+//
+// The network must be healthy to send.
+func (bc *broadcastClient) BroadcastWithAssembler(assembler Assembler, cMixParams cmix.CMIXParams) (
+	rounds.Round, ephemeral.Id, error) {
 	if !bc.net.IsHealthy() {
-		return 0, ephemeral.Id{}, errors.New(errNetworkHealth)
+		return rounds.Round{}, ephemeral.Id{}, errors.New(errNetworkHealth)
 	}
 
-	if len(payload) != bc.maxSymmetricPayload() {
-		return 0, ephemeral.Id{},
-			errors.Errorf(errPayloadSize, len(payload), bc.maxSymmetricPayload())
-	}
+	assemble := func(rid id.Round) (fp format.Fingerprint,
+		service message.Service, encryptedPayload, mac []byte, err error) {
 
-	// Encrypt payload
-	rng := bc.rng.GetStream()
-	encryptedPayload, mac, fp := bc.channel.EncryptSymmetric(payload, rng)
-	rng.Close()
+		//assemble the passed payload
+		payload, err := assembler(rid)
+		if err != nil {
+			return format.Fingerprint{}, message.Service{}, nil, nil, err
+		}
 
-	// Create service using symmetric broadcast service tag & channel reception ID
-	// Allows anybody with this info to listen for messages on this channel
-	service := message.Service{
-		Identifier: bc.channel.ReceptionID.Bytes(),
-		Tag:        symmetricBroadcastServiceTag,
-	}
+		if len(payload) > bc.maxSymmetricPayload() {
+			return format.Fingerprint{}, message.Service{}, nil, nil,
+				errors.Errorf(errPayloadSize, len(payload), bc.maxSymmetricPayload())
+		}
+
+		// Encrypt payload
+		rng := bc.rng.GetStream()
+		defer rng.Close()
+		encryptedPayload, mac, fp, err = bc.channel.EncryptSymmetric(payload,
+			bc.net.GetMaxMessageLength(), rng)
+		if err != nil {
+			return format.Fingerprint{}, message.Service{},
+				nil, nil, err
+		}
+
+		// Create service using symmetric broadcast service tag & channel reception ID
+		// Allows anybody with this info to listen for messages on this channel
+		service = message.Service{
+			Identifier: bc.channel.ReceptionID.Bytes(),
+			Tag:        symmetricBroadcastServiceTag,
+		}
 
-	if cMixParams.DebugTag == cmix.DefaultDebugTag {
-		cMixParams.DebugTag = symmCMixSendTag
+		if cMixParams.DebugTag == cmix.DefaultDebugTag {
+			cMixParams.DebugTag = symmCMixSendTag
+		}
+		return
 	}
 
-	return bc.net.Send(
-		bc.channel.ReceptionID, fp, service, encryptedPayload, mac, cMixParams)
+	return bc.net.SendWithAssembler(bc.channel.ReceptionID, assemble,
+		cMixParams)
 }
diff --git a/broadcast/symmetric_test.go b/broadcast/symmetric_test.go
index 2eb26d29eb3b56db1e894ad5b3da3aaabadf114f..3386a71ead8fb2ffada89329017975216be91507 100644
--- a/broadcast/symmetric_test.go
+++ b/broadcast/symmetric_test.go
@@ -1,12 +1,13 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package broadcast
 
+/*
 import (
 	"bytes"
 	"fmt"
@@ -14,10 +15,9 @@ import (
 	"gitlab.com/elixxir/client/cmix/identity/receptionID"
 	"gitlab.com/elixxir/client/cmix/rounds"
 	crypto "gitlab.com/elixxir/crypto/broadcast"
-	cMixCrypto "gitlab.com/elixxir/crypto/cmix"
+
 	"gitlab.com/elixxir/crypto/fastRNG"
 	"gitlab.com/xx_network/crypto/csprng"
-	"gitlab.com/xx_network/crypto/signature/rsa"
 	"reflect"
 	"sync"
 	"testing"
@@ -38,19 +38,10 @@ func Test_symmetricClient_Smoke(t *testing.T) {
 	rngGen := fastRNG.NewStreamGenerator(1000, 10, csprng.NewSystemRNG)
 	cname := "MyChannel"
 	cdesc := "This is my channel about stuff."
-	csalt := cMixCrypto.NewSalt(csprng.NewSystemRNG(), 32)
-	cpubkey := newRsaPubKey(64, t)
-	cid, err := crypto.NewChannelID(cname, cdesc, csalt, rsa.CreatePublicKeyPem(cpubkey))
-	if err != nil {
-		t.Errorf("Failed to create channel ID: %+v", err)
-	}
-	channel := crypto.Channel{
-		ReceptionID: cid,
-		Name:        cname,
-		Description: cdesc,
-		Salt:        csalt,
-		RsaPubKey:   cpubkey,
-	}
+	mCmix := newMockCmix(cMixHandler)
+	channel,_,_ := crypto.NewChannel(cname, cdesc,
+		mCmix.GetMaxMessageLength(),
+		rngGen.GetStream())
 
 	// Set up callbacks, callback channels, and the symmetric clients
 	const n = 5
@@ -85,7 +76,7 @@ func Test_symmetricClient_Smoke(t *testing.T) {
 
 	// Send broadcast from each client
 	for i := range clients {
-		payload := make([]byte, newMockCmix(cMixHandler).GetMaxMessageLength())
+		payload := make([]byte, clients[i].MaxPayloadSize())
 		copy(payload,
 			fmt.Sprintf("Hello from client %d of %d.", i, len(clients)))
 
@@ -142,10 +133,10 @@ func Test_symmetricClient_Smoke(t *testing.T) {
 	}
 
 	// Broadcast payload
-	_, _, err = clients[0].Broadcast(payload, cmix.GetDefaultCMIXParams())
+	_, _, err := clients[0].Broadcast(payload, cmix.GetDefaultCMIXParams())
 	if err != nil {
 		t.Errorf("Cmix 0 failed to send broadcast: %+v", err)
 	}
 
 	wg.Wait()
-}
+}*/
diff --git a/broadcast/utils_test.go b/broadcast/utils_test.go
index 7bd4ac341a47f98359c76c7a06a5adb70f85f05f..ee1dfebc264c208e037bcbd45385bac6160fa154 100644
--- a/broadcast/utils_test.go
+++ b/broadcast/utils_test.go
@@ -1,40 +1,28 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package broadcast
 
 import (
+	"sync"
+	"time"
+
+	"gitlab.com/xx_network/primitives/id"
+	"gitlab.com/xx_network/primitives/id/ephemeral"
+
 	"gitlab.com/elixxir/client/cmix"
 	"gitlab.com/elixxir/client/cmix/identity/receptionID"
 	"gitlab.com/elixxir/client/cmix/message"
 	"gitlab.com/elixxir/client/cmix/rounds"
 	"gitlab.com/elixxir/primitives/format"
-	"gitlab.com/xx_network/crypto/signature/rsa"
-	"gitlab.com/xx_network/primitives/id"
-	"gitlab.com/xx_network/primitives/id/ephemeral"
-	"math/rand"
-	"sync"
-	"testing"
-	"time"
 )
 
-// newRsaPubKey generates a new random RSA public key for testing.
-func newRsaPubKey(seed int64, t *testing.T) *rsa.PublicKey {
-	prng := rand.New(rand.NewSource(seed))
-	privKey, err := rsa.GenerateKey(prng, 64)
-	if err != nil {
-		t.Errorf("Failed to generate new RSA key: %+v", err)
-	}
-
-	return privKey.GetPublic()
-}
-
 ////////////////////////////////////////////////////////////////////////////////
-// Mock cMix                                                           //
+// Mock cMix                                                                  //
 ////////////////////////////////////////////////////////////////////////////////
 
 type mockCmixHandler struct {
@@ -56,7 +44,7 @@ type mockCmix struct {
 
 func newMockCmix(handler *mockCmixHandler) *mockCmix {
 	return &mockCmix{
-		numPrimeBytes: 4096,
+		numPrimeBytes: 4096 / 8,
 		health:        true,
 		handler:       handler,
 	}
@@ -66,6 +54,30 @@ func (m *mockCmix) GetMaxMessageLength() int {
 	return format.NewMessage(m.numPrimeBytes).ContentsSize()
 }
 
+func (m *mockCmix) SendWithAssembler(recipient *id.ID,
+	assembler cmix.MessageAssembler, _ cmix.CMIXParams) (
+	rounds.Round, ephemeral.Id, error) {
+
+	fingerprint, service, payload, mac, err := assembler(42)
+	if err != nil {
+		panic(err)
+	}
+
+	msg := format.NewMessage(m.numPrimeBytes)
+	msg.SetContents(payload)
+	msg.SetMac(mac)
+	msg.SetKeyFP(fingerprint)
+
+	m.handler.Lock()
+	defer m.handler.Unlock()
+
+	for _, p := range m.handler.processorMap[*recipient][service.Tag] {
+		p.Process(msg, receptionID.EphemeralIdentity{}, rounds.Round{})
+	}
+
+	return rounds.Round{}, ephemeral.Id{}, nil
+}
+
 func (m *mockCmix) Send(recipient *id.ID, fingerprint format.Fingerprint,
 	service message.Service, payload, mac []byte, _ cmix.CMIXParams) (
 	id.Round, ephemeral.Id, error) {
diff --git a/catalog/messageTypes.go b/catalog/messageTypes.go
index 9ab1244631e1c6265e2f8a4a205022f35d943ac0..acadac652c0777e1d58c805a753084547c8f36de 100644
--- a/catalog/messageTypes.go
+++ b/catalog/messageTypes.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package catalog
 
 import "fmt"
diff --git a/catalog/services.go b/catalog/services.go
index 24ab74a466f6499654267861760b72cbc2d6472e..cb5ce516d3bc8cc5babbd8461da161ec23c5d72d 100644
--- a/catalog/services.go
+++ b/catalog/services.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package catalog
 
 import "gitlab.com/elixxir/crypto/sih"
diff --git a/channels/adminListener.go b/channels/adminListener.go
new file mode 100644
index 0000000000000000000000000000000000000000..d9e203f1c0c4bab8be5fa14220130c773fd74ee5
--- /dev/null
+++ b/channels/adminListener.go
@@ -0,0 +1,68 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file                                                               //
+////////////////////////////////////////////////////////////////////////////////
+
+package channels
+
+import (
+	"github.com/golang/protobuf/proto"
+	jww "github.com/spf13/jwalterweatherman"
+	"gitlab.com/elixxir/client/cmix/identity/receptionID"
+	"gitlab.com/elixxir/client/cmix/rounds"
+	"gitlab.com/elixxir/crypto/channel"
+	"gitlab.com/elixxir/primitives/states"
+	"gitlab.com/xx_network/primitives/id"
+)
+
+// adminListener adheres to the [broadcast.ListenerFunc] interface and is used
+// when admin messages are received on the channel.
+type adminListener struct {
+	chID      *id.ID
+	trigger   triggerAdminEventFunc
+	checkSent messageReceiveFunc
+}
+
+// Listen is called when a message is received for the admin listener
+func (al *adminListener) Listen(payload []byte,
+	receptionID receptionID.EphemeralIdentity, round rounds.Round) {
+	// Get the message ID
+	msgID := channel.MakeMessageID(payload, al.chID)
+
+	// Decode the message as a channel message
+	cm := &ChannelMessage{}
+	if err := proto.Unmarshal(payload, cm); err != nil {
+		jww.WARN.Printf("Failed to unmarshal Channel Message from Admin on "+
+			"channel %s", al.chID)
+		return
+	}
+
+	//check if we sent the message, ignore triggering if we sent
+	if al.checkSent(msgID, round) {
+		return
+	}
+
+	/* CRYPTOGRAPHICALLY RELEVANT CHECKS */
+
+	// Check the round to ensure that the message is not a replay
+	if id.Round(cm.RoundID) != round.ID {
+		jww.WARN.Printf("The round message %s send on %s referenced "+
+			"(%d) was not the same as the round the message was found on (%d)",
+			msgID, al.chID, cm.RoundID, round.ID)
+		return
+	}
+
+	// Modify the timestamp to reduce the chance message order will be ambiguous
+	ts := mutateTimestamp(round.Timestamps[states.QUEUED], msgID)
+
+	// Submit the message to the event model for listening
+	if uuid, err := al.trigger(al.chID, cm, ts, msgID, receptionID,
+		round, Delivered); err != nil {
+		jww.WARN.Printf("Error in passing off trigger for admin "+
+			"message (UUID: %d): %+v", uuid, err)
+	}
+
+	return
+}
diff --git a/channels/adminListener_test.go b/channels/adminListener_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..cb571d5724dcd7318d7ab4dec78bd2c0fe14866c
--- /dev/null
+++ b/channels/adminListener_test.go
@@ -0,0 +1,231 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file                                                               //
+////////////////////////////////////////////////////////////////////////////////
+
+package channels
+
+import (
+	"bytes"
+	"gitlab.com/xx_network/primitives/netTime"
+	"testing"
+	"time"
+
+	"github.com/golang/protobuf/proto"
+
+	"gitlab.com/elixxir/client/cmix/identity/receptionID"
+	"gitlab.com/elixxir/client/cmix/rounds"
+	cryptoChannel "gitlab.com/elixxir/crypto/channel"
+	"gitlab.com/elixxir/primitives/states"
+	"gitlab.com/xx_network/primitives/id"
+)
+
+type triggerAdminEventDummy struct {
+	gotData bool
+
+	chID        *id.ID
+	cm          *ChannelMessage
+	msgID       cryptoChannel.MessageID
+	receptionID receptionID.EphemeralIdentity
+	round       rounds.Round
+}
+
+func (taed *triggerAdminEventDummy) triggerAdminEvent(chID *id.ID,
+	cm *ChannelMessage, ts time.Time, messageID cryptoChannel.MessageID,
+	receptionID receptionID.EphemeralIdentity, round rounds.Round,
+	status SentStatus) (uint64, error) {
+	taed.gotData = true
+
+	taed.chID = chID
+	taed.cm = cm
+	taed.msgID = messageID
+	taed.receptionID = receptionID
+	taed.round = round
+
+	return 0, nil
+}
+
+// Tests the happy path.
+func TestAdminListener_Listen(t *testing.T) {
+
+	// Build inputs
+	chID := &id.ID{}
+	chID[0] = 1
+
+	r := rounds.Round{ID: 420, Timestamps: make(map[states.Round]time.Time)}
+	r.Timestamps[states.QUEUED] = netTime.Now()
+
+	cm := &ChannelMessage{
+		Lease:       int64(time.Hour),
+		RoundID:     uint64(r.ID),
+		PayloadType: 42,
+		Payload:     []byte("blarg"),
+	}
+
+	cmSerial, err := proto.Marshal(cm)
+	if err != nil {
+		t.Fatalf("Failed to marshal proto: %+v", err)
+	}
+
+	msgID := cryptoChannel.MakeMessageID(cmSerial, chID)
+
+	// Build the listener
+	dummy := &triggerAdminEventDummy{}
+
+	al := adminListener{
+		chID:      chID,
+		trigger:   dummy.triggerAdminEvent,
+		checkSent: func(messageID cryptoChannel.MessageID, r rounds.Round) bool { return false },
+	}
+
+	// Call the listener
+	al.Listen(cmSerial, receptionID.EphemeralIdentity{}, r)
+
+	// Check the results
+	if !dummy.gotData {
+		t.Fatalf("No data returned after valid listen")
+	}
+
+	if !dummy.chID.Cmp(chID) {
+		t.Errorf("Channel ID not correct: %s vs %s", dummy.chID, chID)
+	}
+
+	if !bytes.Equal(cm.Payload, dummy.cm.Payload) {
+		t.Errorf("payload not correct: %s vs %s", cm.Payload,
+			dummy.cm.Payload)
+	}
+
+	if !msgID.Equals(dummy.msgID) {
+		t.Errorf("messageIDs not correct: %s vs %s", msgID,
+			dummy.msgID)
+	}
+
+	if r.ID != dummy.round.ID {
+		t.Errorf("rounds not correct: %s vs %s", r.ID,
+			dummy.round.ID)
+	}
+}
+
+// Tests that the message is rejected when the round it came on doesn't match
+// the round in the channel message.
+func TestAdminListener_Listen_BadRound(t *testing.T) {
+
+	// build inputs
+	chID := &id.ID{}
+	chID[0] = 1
+
+	r := rounds.Round{ID: 420, Timestamps: make(map[states.Round]time.Time)}
+	r.Timestamps[states.QUEUED] = netTime.Now()
+
+	cm := &ChannelMessage{
+		Lease: int64(time.Hour),
+		// Different from the round above
+		RoundID:     69,
+		PayloadType: 42,
+		Payload:     []byte("blarg"),
+	}
+
+	cmSerial, err := proto.Marshal(cm)
+	if err != nil {
+		t.Fatalf("Failed to marshal proto: %+v", err)
+	}
+
+	// Build the listener
+	dummy := &triggerAdminEventDummy{}
+
+	al := adminListener{
+		chID:      chID,
+		trigger:   dummy.triggerAdminEvent,
+		checkSent: func(messageID cryptoChannel.MessageID, r rounds.Round) bool { return false },
+	}
+
+	// Call the listener
+	al.Listen(cmSerial, receptionID.EphemeralIdentity{}, r)
+
+	// check the results
+	if dummy.gotData {
+		t.Fatalf("payload handled when it should have failed due to " +
+			"a round issue")
+	}
+
+}
+
+// Tests that the message is rejected when the channel message is malformed.
+func TestAdminListener_Listen_BadChannelMessage(t *testing.T) {
+
+	// Build inputs
+	chID := &id.ID{}
+	chID[0] = 1
+
+	r := rounds.Round{ID: 420, Timestamps: make(map[states.Round]time.Time)}
+	r.Timestamps[states.QUEUED] = netTime.Now()
+
+	cmSerial := []byte("blarg")
+
+	// Build the listener
+	dummy := &triggerAdminEventDummy{}
+
+	al := adminListener{
+		chID:      chID,
+		trigger:   dummy.triggerAdminEvent,
+		checkSent: func(messageID cryptoChannel.MessageID, r rounds.Round) bool { return false },
+	}
+
+	// Call the listener
+	al.Listen(cmSerial, receptionID.EphemeralIdentity{}, r)
+
+	// Check the results
+	if dummy.gotData {
+		t.Fatalf("payload handled when it should have failed due to " +
+			"a malformed channel message")
+	}
+
+}
+
+// Tests that the message is rejected when the sized broadcast message is
+// malformed.
+func TestAdminListener_Listen_BadSizedBroadcast(t *testing.T) {
+
+	// build inputs
+	chID := &id.ID{}
+	chID[0] = 1
+
+	r := rounds.Round{ID: 420, Timestamps: make(map[states.Round]time.Time)}
+	r.Timestamps[states.QUEUED] = netTime.Now()
+
+	cm := &ChannelMessage{
+		Lease: int64(time.Hour),
+		// Different from the round above
+		RoundID:     69,
+		PayloadType: 42,
+		Payload:     []byte("blarg"),
+	}
+
+	cmSerial, err := proto.Marshal(cm)
+	if err != nil {
+		t.Fatalf("Failed to marshal proto: %+v", err)
+	}
+
+	// Remove half the sized broadcast to make it malformed
+	chMsgSerialSized := cmSerial[:len(cmSerial)/2]
+
+	// Build the listener
+	dummy := &triggerAdminEventDummy{}
+
+	al := adminListener{
+		chID:      chID,
+		trigger:   dummy.triggerAdminEvent,
+		checkSent: func(messageID cryptoChannel.MessageID, r rounds.Round) bool { return false },
+	}
+
+	// Call the listener
+	al.Listen(chMsgSerialSized, receptionID.EphemeralIdentity{}, r)
+
+	// Check the results
+	if dummy.gotData {
+		t.Fatalf("payload handled when it should have failed due to " +
+			"a malformed sized broadcast")
+	}
+}
diff --git a/channels/channelMessages.pb.go b/channels/channelMessages.pb.go
new file mode 100644
index 0000000000000000000000000000000000000000..911c35da9cfb33b1e319f64233c174f81f1c25d6
--- /dev/null
+++ b/channels/channelMessages.pb.go
@@ -0,0 +1,305 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file                                                               //
+////////////////////////////////////////////////////////////////////////////////
+
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// 	protoc-gen-go v1.27.1
+// 	protoc        v3.15.6
+// source: channelMessages.proto
+
+package channels
+
+import (
+	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+	reflect "reflect"
+	sync "sync"
+)
+
+const (
+	// Verify that this generated code is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+	// Verify that runtime/protoimpl is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+// ChannelMessage is transmitted by the channel. Effectively it is a command for
+// the channel sent by a user with admin access of the channel.
+type ChannelMessage struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	// Lease is the length that this channel message will take effect.
+	Lease int64 `protobuf:"varint,1,opt,name=Lease,proto3" json:"Lease,omitempty"`
+	// The round this message was sent on.
+	RoundID uint64 `protobuf:"varint,2,opt,name=RoundID,proto3" json:"RoundID,omitempty"`
+	// The type the below payload is. This may be some form of channel command,
+	// such as BAN<username1>.
+	PayloadType uint32 `protobuf:"varint,3,opt,name=PayloadType,proto3" json:"PayloadType,omitempty"`
+	// Payload is the actual message payload. It will be processed differently
+	// based on the PayloadType.
+	Payload []byte `protobuf:"bytes,4,opt,name=Payload,proto3" json:"Payload,omitempty"`
+	// nickname is the name which the user is using for this message
+	// it will not be longer than 24 characters
+	Nickname string `protobuf:"bytes,5,opt,name=Nickname,proto3" json:"Nickname,omitempty"`
+	// Nonce is 32 bits of randomness to ensure that two messages in the same
+	// round with that have the same nickname, payload, and lease will not have
+	// the same message ID.
+	Nonce []byte `protobuf:"bytes,6,opt,name=Nonce,proto3" json:"Nonce,omitempty"`
+}
+
+func (x *ChannelMessage) Reset() {
+	*x = ChannelMessage{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_channelMessages_proto_msgTypes[0]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *ChannelMessage) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ChannelMessage) ProtoMessage() {}
+
+func (x *ChannelMessage) ProtoReflect() protoreflect.Message {
+	mi := &file_channelMessages_proto_msgTypes[0]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ChannelMessage.ProtoReflect.Descriptor instead.
+func (*ChannelMessage) Descriptor() ([]byte, []int) {
+	return file_channelMessages_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *ChannelMessage) GetLease() int64 {
+	if x != nil {
+		return x.Lease
+	}
+	return 0
+}
+
+func (x *ChannelMessage) GetRoundID() uint64 {
+	if x != nil {
+		return x.RoundID
+	}
+	return 0
+}
+
+func (x *ChannelMessage) GetPayloadType() uint32 {
+	if x != nil {
+		return x.PayloadType
+	}
+	return 0
+}
+
+func (x *ChannelMessage) GetPayload() []byte {
+	if x != nil {
+		return x.Payload
+	}
+	return nil
+}
+
+func (x *ChannelMessage) GetNickname() string {
+	if x != nil {
+		return x.Nickname
+	}
+	return ""
+}
+
+func (x *ChannelMessage) GetNonce() []byte {
+	if x != nil {
+		return x.Nonce
+	}
+	return nil
+}
+
+// UserMessage is a message sent by a user who is a member within the channel.
+type UserMessage struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	// Message contains the contents of the message. This is typically what the
+	// end-user has submitted to the channel. This is a serialization of the
+	// ChannelMessage.
+	Message []byte `protobuf:"bytes,1,opt,name=Message,proto3" json:"Message,omitempty"`
+	// Signature is the signature proving this message has been sent by the
+	// owner of this user's public key.
+	//
+	//  Signature = Sig(User_ECCPublicKey, Message)
+	Signature []byte `protobuf:"bytes,3,opt,name=Signature,proto3" json:"Signature,omitempty"`
+	// ECCPublicKey is the user's EC Public key. This is provided by the
+	// network.
+	ECCPublicKey []byte `protobuf:"bytes,5,opt,name=ECCPublicKey,proto3" json:"ECCPublicKey,omitempty"`
+}
+
+func (x *UserMessage) Reset() {
+	*x = UserMessage{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_channelMessages_proto_msgTypes[1]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *UserMessage) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*UserMessage) ProtoMessage() {}
+
+func (x *UserMessage) ProtoReflect() protoreflect.Message {
+	mi := &file_channelMessages_proto_msgTypes[1]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use UserMessage.ProtoReflect.Descriptor instead.
+func (*UserMessage) Descriptor() ([]byte, []int) {
+	return file_channelMessages_proto_rawDescGZIP(), []int{1}
+}
+
+func (x *UserMessage) GetMessage() []byte {
+	if x != nil {
+		return x.Message
+	}
+	return nil
+}
+
+func (x *UserMessage) GetSignature() []byte {
+	if x != nil {
+		return x.Signature
+	}
+	return nil
+}
+
+func (x *UserMessage) GetECCPublicKey() []byte {
+	if x != nil {
+		return x.ECCPublicKey
+	}
+	return nil
+}
+
+var File_channelMessages_proto protoreflect.FileDescriptor
+
+var file_channelMessages_proto_rawDesc = []byte{
+	0x0a, 0x15, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65,
+	0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x08, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c,
+	0x73, 0x22, 0xae, 0x01, 0x0a, 0x0e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x4d, 0x65, 0x73,
+	0x73, 0x61, 0x67, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x4c, 0x65, 0x61, 0x73, 0x65, 0x18, 0x01, 0x20,
+	0x01, 0x28, 0x03, 0x52, 0x05, 0x4c, 0x65, 0x61, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x52, 0x6f,
+	0x75, 0x6e, 0x64, 0x49, 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x07, 0x52, 0x6f, 0x75,
+	0x6e, 0x64, 0x49, 0x44, 0x12, 0x20, 0x0a, 0x0b, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x54,
+	0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0b, 0x50, 0x61, 0x79, 0x6c, 0x6f,
+	0x61, 0x64, 0x54, 0x79, 0x70, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61,
+	0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64,
+	0x12, 0x1a, 0x0a, 0x08, 0x4e, 0x69, 0x63, 0x6b, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01,
+	0x28, 0x09, 0x52, 0x08, 0x4e, 0x69, 0x63, 0x6b, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05,
+	0x4e, 0x6f, 0x6e, 0x63, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x4e, 0x6f, 0x6e,
+	0x63, 0x65, 0x22, 0x69, 0x0a, 0x0b, 0x55, 0x73, 0x65, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67,
+	0x65, 0x12, 0x18, 0x0a, 0x07, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01,
+	0x28, 0x0c, 0x52, 0x07, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x53,
+	0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09,
+	0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x12, 0x22, 0x0a, 0x0c, 0x45, 0x43, 0x43,
+	0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52,
+	0x0c, 0x45, 0x43, 0x43, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x42, 0x24, 0x5a,
+	0x22, 0x67, 0x69, 0x74, 0x6c, 0x61, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x65, 0x6c, 0x69, 0x78,
+	0x78, 0x69, 0x72, 0x2f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x2f, 0x63, 0x68, 0x61, 0x6e, 0x6e,
+	0x65, 0x6c, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+}
+
+var (
+	file_channelMessages_proto_rawDescOnce sync.Once
+	file_channelMessages_proto_rawDescData = file_channelMessages_proto_rawDesc
+)
+
+func file_channelMessages_proto_rawDescGZIP() []byte {
+	file_channelMessages_proto_rawDescOnce.Do(func() {
+		file_channelMessages_proto_rawDescData = protoimpl.X.CompressGZIP(file_channelMessages_proto_rawDescData)
+	})
+	return file_channelMessages_proto_rawDescData
+}
+
+var file_channelMessages_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
+var file_channelMessages_proto_goTypes = []interface{}{
+	(*ChannelMessage)(nil), // 0: channels.ChannelMessage
+	(*UserMessage)(nil),    // 1: channels.UserMessage
+}
+var file_channelMessages_proto_depIdxs = []int32{
+	0, // [0:0] is the sub-list for method output_type
+	0, // [0:0] is the sub-list for method input_type
+	0, // [0:0] is the sub-list for extension type_name
+	0, // [0:0] is the sub-list for extension extendee
+	0, // [0:0] is the sub-list for field type_name
+}
+
+func init() { file_channelMessages_proto_init() }
+func file_channelMessages_proto_init() {
+	if File_channelMessages_proto != nil {
+		return
+	}
+	if !protoimpl.UnsafeEnabled {
+		file_channelMessages_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ChannelMessage); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_channelMessages_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*UserMessage); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+	}
+	type x struct{}
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+			RawDescriptor: file_channelMessages_proto_rawDesc,
+			NumEnums:      0,
+			NumMessages:   2,
+			NumExtensions: 0,
+			NumServices:   0,
+		},
+		GoTypes:           file_channelMessages_proto_goTypes,
+		DependencyIndexes: file_channelMessages_proto_depIdxs,
+		MessageInfos:      file_channelMessages_proto_msgTypes,
+	}.Build()
+	File_channelMessages_proto = out.File
+	file_channelMessages_proto_rawDesc = nil
+	file_channelMessages_proto_goTypes = nil
+	file_channelMessages_proto_depIdxs = nil
+}
diff --git a/channels/channelMessages.proto b/channels/channelMessages.proto
new file mode 100644
index 0000000000000000000000000000000000000000..548cfc67c9e8f02a750f12fff45bb27b8b613b4b
--- /dev/null
+++ b/channels/channelMessages.proto
@@ -0,0 +1,57 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file                                                               //
+////////////////////////////////////////////////////////////////////////////////
+
+syntax = "proto3";
+
+option go_package = "gitlab.com/elixxir/client/channels";
+
+package channels;
+
+// ChannelMessage is transmitted by the channel. Effectively it is a command for
+// the channel sent by a user with admin access of the channel.
+message ChannelMessage{
+    // Lease is the length that this channel message will take effect.
+    int64  Lease = 1;
+
+    // The round this message was sent on.
+    uint64 RoundID = 2;
+
+    // The type the below payload is. This may be some form of channel command,
+    // such as BAN<username1>.
+    uint32 PayloadType = 3;
+
+    // Payload is the actual message payload. It will be processed differently
+    // based on the PayloadType.
+    bytes  Payload = 4;
+
+    // nickname is the name which the user is using for this message
+    // it will not be longer than 24 characters
+    string Nickname = 5;
+
+    // Nonce is 32 bits of randomness to ensure that two messages in the same
+    // round with that have the same nickname, payload, and lease will not have
+    // the same message ID.
+    bytes Nonce = 6;
+}
+
+// UserMessage is a message sent by a user who is a member within the channel.
+message UserMessage {
+    // Message contains the contents of the message. This is typically what the
+    // end-user has submitted to the channel. This is a serialization of the
+    // ChannelMessage.
+    bytes  Message = 1;
+
+    // Signature is the signature proving this message has been sent by the
+    // owner of this user's public key.
+    //
+    //  Signature = Sig(User_ECCPublicKey, Message)
+    bytes  Signature = 3;
+
+    // ECCPublicKey is the user's EC Public key. This is provided by the
+    // network.
+    bytes  ECCPublicKey = 5;
+}
\ No newline at end of file
diff --git a/channels/compileProtobuf.sh b/channels/compileProtobuf.sh
new file mode 100644
index 0000000000000000000000000000000000000000..dff697ecd9976fa8330d7c45052f7b3ca8eef382
--- /dev/null
+++ b/channels/compileProtobuf.sh
@@ -0,0 +1,15 @@
+#!/bin/bash
+################################################################################
+## Copyright © 2022 xx foundation                                             ##
+##                                                                            ##
+## Use of this source code is governed by a license that can be found in the  ##
+## LICENSE file.                                                              ##
+################################################################################
+
+# This script will compile the Protobuf file to a Go file (pb.go).
+# This is meant to be called from the top level of the repo.
+
+cd ./channels/ || return
+
+protoc --go_out=. --go_opt=paths=source_relative ./channelMessages.proto
+protoc --go_out=. --go_opt=paths=source_relative ./text.proto
diff --git a/channels/dummyNameServer.go b/channels/dummyNameServer.go
new file mode 100644
index 0000000000000000000000000000000000000000..8c14e40279d8091bf34f29a5a881246715c27c34
--- /dev/null
+++ b/channels/dummyNameServer.go
@@ -0,0 +1,109 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
+package channels
+
+import (
+	"crypto/ed25519"
+	jww "github.com/spf13/jwalterweatherman"
+	"gitlab.com/elixxir/crypto/channel"
+	"gitlab.com/xx_network/primitives/netTime"
+	"io"
+	"time"
+)
+
+// NewDummyNameService returns a dummy object adhering to the name service
+// This neither produces valid signatures nor validates passed signatures.
+//
+// THIS IS FOR DEVELOPMENT AND DEBUGGING PURPOSES ONLY.
+func NewDummyNameService(username string, rng io.Reader) (NameService, error) {
+	jww.WARN.Printf("Creating a Dummy Name Service. This is for " +
+		"development and debugging only. It does not produce valid " +
+		"signatures or verify passed signatures. YOU SHOULD NEVER SEE THIS " +
+		"MESSAGE IN PRODUCTION")
+
+	dns := &dummyNameService{
+		username: username,
+		lease:    netTime.Now().Add(35 * 24 * time.Hour),
+	}
+
+	//generate the private key
+	var err error
+	dns.public, dns.private, err = ed25519.GenerateKey(rng)
+	if err != nil {
+		return nil, err
+	}
+
+	//generate a dummy user discover identity to produce a validation signature
+	//just sign with our own key, it wont be evaluated anyhow
+	dns.validationSig = channel.SignChannelLease(dns.public, dns.username,
+		dns.lease, dns.private)
+
+	return dns, nil
+}
+
+// dummyNameService is a dummy NameService implementation. This is NOT meant
+// for use in production
+type dummyNameService struct {
+	private       ed25519.PrivateKey
+	public        ed25519.PublicKey
+	username      string
+	validationSig []byte
+	lease         time.Time
+}
+
+// GetUsername returns the username for the dummyNameService. This is what was
+// passed in through NewDummyNameService.
+//
+// THIS IS FOR DEVELOPMENT AND DEBUGGING PURPOSES ONLY.
+func (dns *dummyNameService) GetUsername() string {
+	return dns.username
+}
+
+// GetChannelValidationSignature will return the dummy validation signature
+// generated in through the constructor, NewDummyNameService.
+//
+// THIS IS FOR DEVELOPMENT AND DEBUGGING PURPOSES ONLY.
+func (dns *dummyNameService) GetChannelValidationSignature() ([]byte, time.Time) {
+	jww.WARN.Printf("GetChannelValidationSignature called on Dummy Name " +
+		"Service, dummy signature from a random key returned - identity not " +
+		"proven. YOU SHOULD NEVER SEE THIS MESSAGE IN PRODUCTION")
+	return dns.validationSig, dns.lease
+}
+
+// GetChannelPubkey returns the ed25519.PublicKey generates in the constructor,
+// NewDummyNameService.
+func (dns *dummyNameService) GetChannelPubkey() ed25519.PublicKey {
+	return dns.public
+}
+
+// SignChannelMessage will sign the passed in message using the
+// dummyNameService's private key.
+//
+// THIS IS FOR DEVELOPMENT AND DEBUGGING PURPOSES ONLY.
+func (dns *dummyNameService) SignChannelMessage(message []byte) (
+	signature []byte, err error) {
+	jww.WARN.Printf("SignChannelMessage called on Dummy Name Service, " +
+		"signature from a random key - identity not proven. YOU SHOULD " +
+		"NEVER SEE THIS MESSAGE IN PRODUCTION")
+	sig := ed25519.Sign(dns.private, message)
+	return sig, nil
+}
+
+// ValidateChannelMessage will always return true, indicating the the channel
+// message is valid. This will ignore the passed in arguments. As a result,
+// these values may be dummy or precanned.
+//
+// THIS IS FOR DEVELOPMENT AND DEBUGGING PURPOSES ONLY.
+func (dns *dummyNameService) ValidateChannelMessage(username string, lease time.Time,
+	pubKey ed25519.PublicKey, authorIDSignature []byte) bool {
+	//ignore the authorIDSignature
+	jww.WARN.Printf("ValidateChannelMessage called on Dummy Name Service, " +
+		"no validation done - identity not validated. YOU SHOULD NEVER SEE " +
+		"THIS MESSAGE IN PRODUCTION")
+	return true
+}
diff --git a/channels/dummyNameServer_test.go b/channels/dummyNameServer_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..183da2abaa10cbd811048023c6447f61f3261ae4
--- /dev/null
+++ b/channels/dummyNameServer_test.go
@@ -0,0 +1,126 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
+package channels
+
+import (
+	"crypto/ed25519"
+	"gitlab.com/xx_network/crypto/csprng"
+	"gitlab.com/xx_network/primitives/netTime"
+	"testing"
+)
+
+const numTests = 10
+
+// Smoke test.
+func TestNewDummyNameService(t *testing.T) {
+	rng := csprng.NewSystemRNG()
+	username := "floridaMan"
+	_, err := NewDummyNameService(username, rng)
+	if err != nil {
+		t.Fatalf("NewDummyNameService error: %+v", err)
+	}
+
+}
+
+// Smoke test.
+func TestDummyNameService_GetUsername(t *testing.T) {
+	rng := csprng.NewSystemRNG()
+	username := "floridaMan"
+	ns, err := NewDummyNameService(username, rng)
+	if err != nil {
+		t.Fatalf("NewDummyNameService error: %+v", err)
+	}
+
+	if username != ns.GetUsername() {
+		t.Fatalf("GetUsername did not return expected value."+
+			"\nExpected: %s"+
+			"\nReceived: %s", username, ns.GetUsername())
+	}
+
+}
+
+// Smoke test.
+func TestDummyNameService_SignChannelMessage(t *testing.T) {
+	rng := csprng.NewSystemRNG()
+	username := "floridaMan"
+	ns, err := NewDummyNameService(username, rng)
+	if err != nil {
+		t.Fatalf("NewDummyNameService error: %+v", err)
+	}
+
+	message := []byte("the secret is in the sauce.")
+
+	signature, err := ns.SignChannelMessage(message)
+	if err != nil {
+		t.Fatalf("SignChannelMessage error: %v", err)
+	}
+
+	if len(signature) != ed25519.SignatureSize {
+		t.Errorf("DummyNameService's SignChannelMessage did not return a "+
+			"signature of expected size, according to ed25519 specifications."+
+			"\nExpected: %d"+
+			"\nReceived: %d", ed25519.SignatureSize, len(signature))
+	}
+
+}
+
+// Smoke test.
+func TestDummyNameService_GetChannelValidationSignature(t *testing.T) {
+	rng := csprng.NewSystemRNG()
+	username := "floridaMan"
+	ns, err := NewDummyNameService(username, rng)
+	if err != nil {
+		t.Fatalf("NewDummyNameService error: %+v", err)
+	}
+
+	validationSig, _ := ns.GetChannelValidationSignature()
+
+	if len(validationSig) != ed25519.SignatureSize {
+		t.Errorf("DummyNameService's GetChannelValidationSignature did not "+
+			"return a validation signature of expected size, according to "+
+			"ed25519 specifications."+
+			"\nExpected: %d"+
+			"\nReceived: %d", ed25519.SignatureSize, len(validationSig))
+	}
+
+}
+
+// Smoke test.
+func TestDummyNameService_ValidateChannelMessage(t *testing.T) {
+	rng := csprng.NewSystemRNG()
+	username := "floridaMan"
+	ns, err := NewDummyNameService(username, rng)
+	if err != nil {
+		t.Fatalf("NewDummyNameService error: %+v", err)
+	}
+
+	for i := 0; i < numTests; i++ {
+		if !ns.ValidateChannelMessage(username, netTime.Now(), nil, nil) {
+			t.Errorf("ValidateChannelMessage returned false. This should " +
+				"only ever return true.")
+		}
+	}
+}
+
+// Smoke test.
+func TestDummyNameService_GetChannelPubkey(t *testing.T) {
+	rng := csprng.NewSystemRNG()
+	username := "floridaMan"
+	ns, err := NewDummyNameService(username, rng)
+	if err != nil {
+		t.Fatalf("NewDummyNameService error: %+v", err)
+	}
+
+	if len(ns.GetChannelPubkey()) != ed25519.PublicKeySize {
+		t.Errorf("DummyNameService's GetChannelPubkey did not "+
+			"return a validation signature of expected size, according to "+
+			"ed25519 specifications."+
+			"\nExpected: %d"+
+			"\nReceived: %d", ed25519.PublicKeySize, ns.GetChannelPubkey())
+	}
+}
diff --git a/channels/emoji.go b/channels/emoji.go
new file mode 100644
index 0000000000000000000000000000000000000000..71c7ae4f66dd6b96e812521056f44a548fbf74c6
--- /dev/null
+++ b/channels/emoji.go
@@ -0,0 +1,37 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file                                                               //
+////////////////////////////////////////////////////////////////////////////////
+
+package channels
+
+import (
+	"bytes"
+	"regexp"
+)
+
+//based on emojis found at https://unicode.org/emoji/charts/full-emoji-list.html
+const findEmoji = `[\xA9\xAE\x{2000}-\x{3300}\x{1F000}-\x{1FBFF}]`
+
+var compiledFindEmoji = regexp.MustCompile(findEmoji)
+
+// ValidateReaction checks that the reaction only contains a single emoji.
+func ValidateReaction(reaction string) error {
+
+	//make sure it is only only character
+	reactRunes := []rune(reaction)
+	if len(reactRunes) > 1 {
+		return InvalidReaction
+	}
+
+	reader := bytes.NewReader([]byte(reaction))
+
+	// make sure it has emojis
+	if !compiledFindEmoji.MatchReader(reader) {
+		return InvalidReaction
+	}
+
+	return nil
+}
diff --git a/channels/emoji_test.go b/channels/emoji_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..d320b05a6b0a404f23d3412aca8fb6a1fea393ef
--- /dev/null
+++ b/channels/emoji_test.go
@@ -0,0 +1,35 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file                                                               //
+////////////////////////////////////////////////////////////////////////////////
+
+package channels
+
+import (
+	"testing"
+)
+
+func TestValidateReaction(t *testing.T) {
+
+	testReactions := []string{"🍆", "😂", "❤", "🤣", "👍", "😭", "🙏", "😘", "🥰",
+		"😍", "😊", "☺", "A", "b", "AA", "1", "🍆🍆", "🍆A", "👍👍👍", "👍😘A",
+		"O", "\u0000", "\u0011", "\u001F", "\u007F", "\u0080", "\u008A",
+		"\u009F"}
+
+	expected := []error{
+		nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil,
+		InvalidReaction, InvalidReaction, InvalidReaction, InvalidReaction,
+		InvalidReaction, InvalidReaction, InvalidReaction, InvalidReaction,
+		InvalidReaction, InvalidReaction, InvalidReaction, InvalidReaction,
+		InvalidReaction, InvalidReaction, InvalidReaction, InvalidReaction}
+
+	for i, r := range testReactions {
+		err := ValidateReaction(r)
+		if err != expected[i] {
+			t.Errorf("Got incorrect response for `%s` (%d): "+
+				"`%s` vs `%s`", r, i, err, expected[i])
+		}
+	}
+}
diff --git a/channels/errors.go b/channels/errors.go
new file mode 100644
index 0000000000000000000000000000000000000000..319f065966a899f5a64c05b41eda84caa887fd02
--- /dev/null
+++ b/channels/errors.go
@@ -0,0 +1,25 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file                                                               //
+////////////////////////////////////////////////////////////////////////////////
+
+package channels
+
+import "github.com/pkg/errors"
+
+var (
+	ChannelAlreadyExistsErr = errors.New(
+		"the channel cannot be added because it already exists")
+	ChannelDoesNotExistsErr = errors.New(
+		"the channel cannot be found")
+	MessageTooLongErr = errors.New(
+		"the passed message is too long")
+	WrongPrivateKey = errors.New(
+		"the passed private key does not match the channel")
+	MessageTypeAlreadyRegistered = errors.New("the given message type has " +
+		"already been registered")
+	InvalidReaction = errors.New(
+		"The reaction is not valid, it must be a single emoji")
+)
diff --git a/channels/eventModel.go b/channels/eventModel.go
new file mode 100644
index 0000000000000000000000000000000000000000..26db7539a4b8b5635b7dbfdb39b1714fa180199d
--- /dev/null
+++ b/channels/eventModel.go
@@ -0,0 +1,358 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file                                                               //
+////////////////////////////////////////////////////////////////////////////////
+
+package channels
+
+import (
+	"errors"
+	"fmt"
+	"github.com/golang/protobuf/proto"
+	jww "github.com/spf13/jwalterweatherman"
+	"gitlab.com/elixxir/client/cmix/identity/receptionID"
+	"sync"
+	"time"
+
+	"gitlab.com/elixxir/client/cmix/rounds"
+	cryptoBroadcast "gitlab.com/elixxir/crypto/broadcast"
+	cryptoChannel "gitlab.com/elixxir/crypto/channel"
+	"gitlab.com/xx_network/primitives/id"
+)
+
+// AdminUsername defines the displayed username of admin messages, which are
+// unique users for every channel defined by the channel's private key.
+const AdminUsername = "Admin"
+
+type SentStatus uint8
+
+const (
+	Unsent SentStatus = iota
+	Sent
+	Delivered
+	Failed
+)
+
+// EventModel is an interface which an external party which uses the channels
+// system passed an object which adheres to in order to get events on the
+// channel.
+type EventModel interface {
+	// JoinChannel is called whenever a channel is joined locally.
+	JoinChannel(channel *cryptoBroadcast.Channel)
+
+	// LeaveChannel is called whenever a channel is left locally.
+	LeaveChannel(channelID *id.ID)
+
+	// ReceiveMessage is called whenever a message is received on a given
+	// channel. It may be called multiple times on the same message. It is
+	// incumbent on the user of the API to filter such called by message ID.
+	//
+	// the api needs to return a uuid of the message which it may be
+	// referenced at a later time
+	//
+	// messageID, timestamp, and round are all nillable and may be updated
+	// based upon the UUID at a later date. A time of time.Time{} will be
+	// passed for a nilled timestamp.
+	//
+	// Nickname may be empty, in which case the UI is expected to display
+	// the codename
+	//
+	// Message type is included in the call, it will always be Text (1)
+	// for this call, but it may be required in downstream databases
+	ReceiveMessage(channelID *id.ID, messageID cryptoChannel.MessageID,
+		nickname, text string, identity cryptoChannel.Identity,
+		timestamp time.Time, lease time.Duration, round rounds.Round,
+		mType MessageType, status SentStatus) uint64
+
+	// ReceiveReply is called whenever a message is received that is a reply on
+	// a given channel. It may be called multiple times on the same message. It
+	// is incumbent on the user of the API to filter such called by message ID.
+	//
+	// Messages may arrive our of order, so a reply in theory can arrive before
+	// the initial message. As a result, it may be important to buffer replies.
+	//
+	// the api needs to return a uuid of the message which it may be
+	// referenced at a later time
+	//
+	// messageID, timestamp, and round are all nillable and may be updated
+	// based upon the UUID at a later date. A time of time.Time{} will be
+	// passed for a nilled timestamp.
+	//
+	// Nickname may be empty, in which case the UI is expected to display
+	// the codename
+	//
+	// Message type is included in the call, it will always be Text (1) for
+	// this call, but it may be required in downstream databases
+	ReceiveReply(channelID *id.ID, messageID cryptoChannel.MessageID,
+		reactionTo cryptoChannel.MessageID, nickname, text string,
+		identity cryptoChannel.Identity, timestamp time.Time,
+		lease time.Duration, round rounds.Round, mType MessageType,
+		status SentStatus) uint64
+
+	// ReceiveReaction is called whenever a reaction to a message is received
+	// on a given channel. It may be called multiple times on the same reaction.
+	// It is incumbent on the user of the API to filter such called by message
+	// ID.
+	//
+	// Messages may arrive our of order, so a reply in theory can arrive before
+	// the initial message. As a result, it may be important to buffer
+	// reactions.
+	//
+	// the api needs to return a uuid of the message which it may be
+	// referenced at a later time
+	//
+	// messageID, timestamp, and round are all nillable and may be updated
+	// based upon the UUID at a later date. A time of time.Time{} will be
+	// passed for a nilled timestamp.
+	//
+	// Nickname may be empty, in which case the UI is expected to display
+	// the codename
+	//
+	// Message type is included in the call, it will always be Reaction (3) for
+	// this call, but it may be required in downstream databases
+	ReceiveReaction(channelID *id.ID, messageID cryptoChannel.MessageID,
+		reactionTo cryptoChannel.MessageID, nickname, reaction string,
+		identity cryptoChannel.Identity, timestamp time.Time,
+		lease time.Duration, round rounds.Round, mType MessageType,
+		status SentStatus) uint64
+
+	// UpdateSentStatus is called whenever the sent status of a message has
+	// changed.
+	//
+	// messageID, timestamp, and round are all nillable and may be updated
+	// based upon the UUID at a later date. A time of time.Time{} will be
+	// passed for a nilled timestamp. If a nil value is passed, make no update
+	UpdateSentStatus(uuid uint64, messageID cryptoChannel.MessageID,
+		timestamp time.Time, round rounds.Round, status SentStatus)
+
+	// unimplemented
+	// IgnoreMessage(ChannelID *id.ID, MessageID cryptoChannel.MessageID)
+	// UnIgnoreMessage(ChannelID *id.ID, MessageID cryptoChannel.MessageID)
+	// PinMessage(ChannelID *id.ID, MessageID cryptoChannel.MessageID, end time.Time)
+	// UnPinMessage(ChannelID *id.ID, MessageID cryptoChannel.MessageID)
+}
+
+// MessageTypeReceiveMessage defines handlers for messages of various message
+// types. Default ones for Text, Reaction, and AdminText.
+// A unique uuid must be returned by which the message can be referenced later
+// via UpdateSentStatus
+// It must return a unique UUID for the message by which it can be referenced
+// later
+type MessageTypeReceiveMessage func(channelID *id.ID,
+	messageID cryptoChannel.MessageID, messageType MessageType,
+	nickname string, content []byte, identity cryptoChannel.Identity,
+	timestamp time.Time, lease time.Duration, round rounds.Round,
+	status SentStatus) uint64
+
+// updateStatusFunc is a function type for EventModel.UpdateSentStatus so it can
+// be mocked for testing where used.
+type updateStatusFunc func(uuid uint64, messageID cryptoChannel.MessageID,
+	timestamp time.Time, round rounds.Round, status SentStatus)
+
+// events is an internal structure that processes events and stores the handlers
+// for those events.
+type events struct {
+	model      EventModel
+	registered map[MessageType]MessageTypeReceiveMessage
+	mux        sync.RWMutex
+}
+
+// initEvents initializes the event model and registers default message type
+// handlers.
+func initEvents(model EventModel) *events {
+	e := &events{
+		model:      model,
+		registered: make(map[MessageType]MessageTypeReceiveMessage),
+		mux:        sync.RWMutex{},
+	}
+
+	// set up default message types
+	e.registered[Text] = e.receiveTextMessage
+	e.registered[AdminText] = e.receiveTextMessage
+	e.registered[Reaction] = e.receiveReaction
+	return e
+}
+
+// RegisterReceiveHandler is used to register handlers for non default message
+// types s they can be processed by modules. It is important that such modules
+// sync up with the event model implementation.
+//
+// There can only be one handler per message type, and this will return an error
+// on a multiple registration.
+func (e *events) RegisterReceiveHandler(messageType MessageType,
+	listener MessageTypeReceiveMessage) error {
+	e.mux.Lock()
+	defer e.mux.Unlock()
+
+	// check if the type is already registered
+	if _, exists := e.registered[messageType]; exists {
+		return MessageTypeAlreadyRegistered
+	}
+
+	// register the message type
+	e.registered[messageType] = listener
+	jww.INFO.Printf("Registered Listener for Message Type %s", messageType)
+	return nil
+}
+
+type triggerEventFunc func(chID *id.ID, umi *userMessageInternal, ts time.Time,
+	receptionID receptionID.EphemeralIdentity, round rounds.Round,
+	status SentStatus) (uint64, error)
+
+// triggerEvent is an internal function that is used to trigger message
+// reception on a message received from a user (symmetric encryption).
+//
+// It will call the appropriate MessageTypeHandler assuming one exists.
+func (e *events) triggerEvent(chID *id.ID, umi *userMessageInternal, ts time.Time,
+	receptionID receptionID.EphemeralIdentity, round rounds.Round,
+	status SentStatus) (uint64, error) {
+	um := umi.GetUserMessage()
+	cm := umi.GetChannelMessage()
+	messageType := MessageType(cm.PayloadType)
+
+	identity := cryptoChannel.ConstructIdentity(um.ECCPublicKey)
+
+	// Check if the type is already registered
+	e.mux.RLock()
+	listener, exists := e.registered[messageType]
+	e.mux.RUnlock()
+	if !exists {
+		errStr := fmt.Sprintf("Received message from %s on channel %s in "+
+			"round %d which could not be handled due to unregistered message "+
+			"type %s; Contents: %v", identity.Codename, chID, round.ID, messageType,
+			cm.Payload)
+		jww.WARN.Printf(errStr)
+		return 0, errors.New(errStr)
+	}
+
+	// Call the listener. This is already in an instanced event, no new thread needed.
+	uuid := listener(chID, umi.GetMessageID(), messageType, cm.Nickname, cm.Payload, identity,
+		ts, time.Duration(cm.Lease), round, status)
+	return uuid, nil
+}
+
+type triggerAdminEventFunc func(chID *id.ID, cm *ChannelMessage, ts time.Time,
+	messageID cryptoChannel.MessageID, receptionID receptionID.EphemeralIdentity,
+	round rounds.Round, status SentStatus) (uint64, error)
+
+// triggerAdminEvent is an internal function that is used to trigger message
+// reception on a message received from the admin (asymmetric encryption).
+//
+// It will call the appropriate MessageTypeHandler assuming one exists.
+func (e *events) triggerAdminEvent(chID *id.ID, cm *ChannelMessage,
+	ts time.Time, messageID cryptoChannel.MessageID,
+	receptionID receptionID.EphemeralIdentity, round rounds.Round,
+	status SentStatus) (uint64, error) {
+	messageType := MessageType(cm.PayloadType)
+
+	// check if the type is already registered
+	e.mux.RLock()
+	listener, exists := e.registered[messageType]
+	e.mux.RUnlock()
+	if !exists {
+		errStr := fmt.Sprintf("Received Admin message from %s on channel %s in "+
+			"round %d which could not be handled due to unregistered message "+
+			"type %s; Contents: %v", AdminUsername, chID, round.ID, messageType,
+			cm.Payload)
+		jww.WARN.Printf(errStr)
+		return 0, errors.New(errStr)
+	}
+
+	// Call the listener. This is already in an instanced event, no new thread needed.
+	uuid := listener(chID, messageID, messageType, AdminUsername, cm.Payload,
+		cryptoChannel.Identity{Codename: AdminUsername}, ts,
+		time.Duration(cm.Lease), round, status)
+	return uuid, nil
+}
+
+// receiveTextMessage is the internal function that handles the reception of
+// text messages. It handles both messages and replies and calls the correct
+// function on the event model.
+//
+// If the message has a reply, but it is malformed, it will drop the reply and
+// write to the log.
+func (e *events) receiveTextMessage(channelID *id.ID,
+	messageID cryptoChannel.MessageID, messageType MessageType,
+	nickname string, content []byte, identity cryptoChannel.Identity,
+	timestamp time.Time, lease time.Duration, round rounds.Round,
+	status SentStatus) uint64 {
+	txt := &CMIXChannelText{}
+
+	if err := proto.Unmarshal(content, txt); err != nil {
+		jww.ERROR.Printf("Failed to text unmarshal message %s from %s on "+
+			"channel %s, type %s, ts: %s, lease: %s, round: %d: %+v",
+			messageID, identity.Codename, channelID, messageType, timestamp, lease,
+			round.ID, err)
+		return 0
+	}
+
+	if txt.ReplyMessageID != nil {
+
+		if len(txt.ReplyMessageID) == cryptoChannel.MessageIDLen {
+			var replyTo cryptoChannel.MessageID
+			copy(replyTo[:], txt.ReplyMessageID)
+			return e.model.ReceiveReply(channelID, messageID, replyTo,
+				nickname, txt.Text, identity, timestamp, lease, round, Text, status)
+
+		} else {
+			jww.ERROR.Printf("Failed process reply to for message %s from %s on "+
+				"channel %s, type %s, ts: %s, lease: %s, round: %d, returning "+
+				"without reply",
+				messageID, identity.Codename, channelID, messageType, timestamp, lease,
+				round.ID)
+			// Still process the message, but drop the reply because it is
+			// malformed
+		}
+	}
+
+	return e.model.ReceiveMessage(channelID, messageID, nickname, txt.Text, identity,
+		timestamp, lease, round, Text, status)
+}
+
+// receiveReaction is the internal function that handles the reception of
+// Reactions.
+//
+// It does edge checking to ensure the received reaction is just a single emoji.
+// If the received reaction is not, the reaction is dropped.
+// If the messageID for the message the reaction is to is malformed, the
+// reaction is dropped.
+func (e *events) receiveReaction(channelID *id.ID,
+	messageID cryptoChannel.MessageID, messageType MessageType,
+	nickname string, content []byte, identity cryptoChannel.Identity,
+	timestamp time.Time, lease time.Duration, round rounds.Round,
+	status SentStatus) uint64 {
+	react := &CMIXChannelReaction{}
+	if err := proto.Unmarshal(content, react); err != nil {
+		jww.ERROR.Printf("Failed to text unmarshal message %s from %s on "+
+			"channel %s, type %s, ts: %s, lease: %s, round: %d: %+v",
+			messageID, identity.Codename, channelID, messageType, timestamp, lease,
+			round.ID, err)
+		return 0
+	}
+
+	// check that the reaction is a single emoji and ignore if it isn't
+	if err := ValidateReaction(react.Reaction); err != nil {
+		jww.ERROR.Printf("Failed process reaction %s from %s on channel "+
+			"%s, type %s, ts: %s, lease: %s, round: %d, due to malformed "+
+			"reaction (%s), ignoring reaction",
+			messageID, identity.Codename, channelID, messageType, timestamp, lease,
+			round.ID, err)
+		return 0
+	}
+
+	if react.ReactionMessageID != nil && len(react.ReactionMessageID) == cryptoChannel.MessageIDLen {
+		var reactTo cryptoChannel.MessageID
+		copy(reactTo[:], react.ReactionMessageID)
+		return e.model.ReceiveReaction(channelID, messageID, reactTo, nickname,
+			react.Reaction, identity, timestamp, lease, round, Reaction, status)
+	} else {
+		jww.ERROR.Printf("Failed process reaction %s from %s on channel "+
+			"%s, type %s, ts: %s, lease: %s, round: %d, reacting to "+
+			"invalid message, ignoring reaction",
+			messageID, identity.Codename, channelID, messageType, timestamp, lease,
+			round.ID)
+	}
+	return 0
+}
diff --git a/channels/eventModel_test.go b/channels/eventModel_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..89f30f3ef36a5362a94eb33746d76a6c976e339d
--- /dev/null
+++ b/channels/eventModel_test.go
@@ -0,0 +1,905 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file                                                               //
+////////////////////////////////////////////////////////////////////////////////
+
+package channels
+
+import (
+	"bytes"
+	"fmt"
+	"github.com/golang/protobuf/proto"
+	"gitlab.com/elixxir/client/cmix/identity/receptionID"
+	"gitlab.com/elixxir/client/cmix/rounds"
+	cryptoBroadcast "gitlab.com/elixxir/crypto/broadcast"
+	cryptoChannel "gitlab.com/elixxir/crypto/channel"
+	"gitlab.com/elixxir/primitives/states"
+	"gitlab.com/xx_network/primitives/id"
+	"gitlab.com/xx_network/primitives/netTime"
+	"math/rand"
+	"reflect"
+	"runtime"
+	"testing"
+	"time"
+)
+
+type eventReceive struct {
+	channelID  *id.ID
+	messageID  cryptoChannel.MessageID
+	reactionTo cryptoChannel.MessageID
+	nickname   string
+	content    []byte
+	timestamp  time.Time
+	lease      time.Duration
+	round      rounds.Round
+}
+
+type MockEvent struct {
+	uuid uint64
+	eventReceive
+}
+
+func (m *MockEvent) getUUID() uint64 {
+	old := m.uuid
+	m.uuid++
+	return old
+}
+
+func (m *MockEvent) UpdateSentStatus(uuid uint64, messageID cryptoChannel.MessageID,
+	timestamp time.Time, round rounds.Round, status SentStatus) {
+	//TODO implement me
+	panic("implement me")
+}
+
+func (*MockEvent) JoinChannel(channel *cryptoBroadcast.Channel) {}
+func (*MockEvent) LeaveChannel(channelID *id.ID)                {}
+func (m *MockEvent) ReceiveMessage(channelID *id.ID, messageID cryptoChannel.MessageID,
+	nickname, text string, identity cryptoChannel.Identity,
+	timestamp time.Time, lease time.Duration, round rounds.Round,
+	mType MessageType, status SentStatus) uint64 {
+	m.eventReceive = eventReceive{
+		channelID:  channelID,
+		messageID:  messageID,
+		reactionTo: cryptoChannel.MessageID{},
+		nickname:   nickname,
+		content:    []byte(text),
+		timestamp:  timestamp,
+		lease:      lease,
+		round:      round,
+	}
+	return m.getUUID()
+}
+func (m *MockEvent) ReceiveReply(channelID *id.ID, messageID cryptoChannel.MessageID,
+	reactionTo cryptoChannel.MessageID, nickname, text string,
+	identity cryptoChannel.Identity, timestamp time.Time,
+	lease time.Duration, round rounds.Round, mType MessageType, status SentStatus) uint64 {
+	fmt.Println(reactionTo)
+	m.eventReceive = eventReceive{
+		channelID:  channelID,
+		messageID:  messageID,
+		reactionTo: reactionTo,
+		nickname:   nickname,
+		content:    []byte(text),
+		timestamp:  timestamp,
+		lease:      lease,
+		round:      round,
+	}
+	return m.getUUID()
+}
+func (m *MockEvent) ReceiveReaction(channelID *id.ID, messageID cryptoChannel.MessageID,
+	reactionTo cryptoChannel.MessageID, nickname, reaction string,
+	identity cryptoChannel.Identity, timestamp time.Time,
+	lease time.Duration, round rounds.Round, mType MessageType, status SentStatus) uint64 {
+	m.eventReceive = eventReceive{
+		channelID:  channelID,
+		messageID:  messageID,
+		reactionTo: reactionTo,
+		nickname:   nickname,
+		content:    []byte(reaction),
+		timestamp:  timestamp,
+		lease:      lease,
+		round:      round,
+	}
+	return m.getUUID()
+}
+
+func Test_initEvents(t *testing.T) {
+
+	me := &MockEvent{}
+
+	e := initEvents(me)
+
+	// verify the model is registered
+	if e.model != me {
+		t.Errorf("Event model is not registered")
+	}
+
+	// check registered channels was created
+	if e.registered == nil {
+		t.Fatalf("Registered handlers is not registered")
+	}
+
+	// check that all the default callbacks are registered
+	if len(e.registered) != 3 {
+		t.Errorf("The correct number of default handlers are not "+
+			"registered; %d vs %d", len(e.registered), 3)
+		//If this fails, is means the default handlers have changed. edit the
+		//number here and add tests below. be suspicious if it goes down.
+	}
+
+	if getFuncName(e.registered[Text]) != getFuncName(e.receiveTextMessage) {
+		t.Errorf("Text does not have recieveTextMessageRegistred")
+	}
+
+	if getFuncName(e.registered[AdminText]) != getFuncName(e.receiveTextMessage) {
+		t.Errorf("AdminText does not have recieveTextMessageRegistred")
+	}
+
+	if getFuncName(e.registered[Reaction]) != getFuncName(e.receiveReaction) {
+		t.Errorf("Reaction does not have recieveReaction")
+	}
+}
+
+func TestEvents_RegisterReceiveHandler(t *testing.T) {
+	me := &MockEvent{}
+
+	e := initEvents(me)
+
+	//test that a new receive handler can be registered.
+	mt := MessageType(42)
+	err := e.RegisterReceiveHandler(mt, e.receiveReaction)
+	if err != nil {
+		t.Fatalf("Failed to register '%s' when it should be "+
+			"sucesfull: %+v", mt, err)
+	}
+
+	//check that it is written
+	returnedHandler, exists := e.registered[mt]
+	if !exists {
+		t.Fatalf("Failed to get handler '%s' after registration", mt)
+	}
+
+	//check that the correct function is written
+	if getFuncName(e.receiveReaction) != getFuncName(returnedHandler) {
+		t.Fatalf("Failed to get correct handler for '%s' after "+
+			"registration, %s vs %s", mt, getFuncName(e.receiveReaction),
+			getFuncName(returnedHandler))
+	}
+
+	//test that writing to the same receive handler fails
+	err = e.RegisterReceiveHandler(mt, e.receiveTextMessage)
+	if err == nil {
+		t.Fatalf("Failed to register '%s' when it should be "+
+			"sucesfull: %+v", mt, err)
+	} else if err != MessageTypeAlreadyRegistered {
+		t.Fatalf("Wrong error returned when reregierting message "+
+			"tyle '%s': %+v", mt, err)
+	}
+
+	//check that it is still written
+	returnedHandler, exists = e.registered[mt]
+	if !exists {
+		t.Fatalf("Failed to get handler '%s' after second "+
+			"registration", mt)
+	}
+
+	//check that the correct function is written
+	if getFuncName(e.receiveReaction) != getFuncName(returnedHandler) {
+		t.Fatalf("Failed to get correct handler for '%s' after "+
+			"second registration, %s vs %s", mt, getFuncName(e.receiveReaction),
+			getFuncName(returnedHandler))
+	}
+}
+
+type dummyMessageTypeHandler struct {
+	triggered   bool
+	channelID   *id.ID
+	messageID   cryptoChannel.MessageID
+	messageType MessageType
+	nickname    string
+	content     []byte
+	timestamp   time.Time
+	lease       time.Duration
+	round       rounds.Round
+}
+
+func (dmth *dummyMessageTypeHandler) dummyMessageTypeReceiveMessage(channelID *id.ID,
+	messageID cryptoChannel.MessageID, messageType MessageType,
+	nickname string, content []byte, identity cryptoChannel.Identity,
+	timestamp time.Time, lease time.Duration, round rounds.Round,
+	status SentStatus) uint64 {
+	dmth.triggered = true
+	dmth.channelID = channelID
+	dmth.messageID = messageID
+	dmth.messageType = messageType
+	dmth.nickname = nickname
+	dmth.content = content
+	dmth.timestamp = timestamp
+	dmth.lease = lease
+	dmth.round = round
+	return rand.Uint64()
+}
+
+func TestEvents_triggerEvents(t *testing.T) {
+	me := &MockEvent{}
+
+	e := initEvents(me)
+
+	dummy := &dummyMessageTypeHandler{}
+
+	//register the handler
+	mt := MessageType(42)
+	err := e.RegisterReceiveHandler(mt, dummy.dummyMessageTypeReceiveMessage)
+	if err != nil {
+		t.Fatalf("Error on registration, should not have happened: "+
+			"%+v", err)
+	}
+
+	//craft the input for the event
+	chID := &id.ID{}
+	chID[0] = 1
+
+	umi, _, _ := builtTestUMI(t, mt)
+
+	r := rounds.Round{ID: 420, Timestamps: make(map[states.Round]time.Time)}
+	r.Timestamps[states.QUEUED] = netTime.Now()
+
+	//call the trigger
+	_, err = e.triggerEvent(chID, umi, netTime.Now(), receptionID.EphemeralIdentity{}, r, Delivered)
+	if err != nil {
+		t.Fatalf(err.Error())
+	}
+	//check that the event was triggered
+	if !dummy.triggered {
+		t.Errorf("The event was not triggered")
+	}
+
+	//check the data is stored in the dummy
+	if !dummy.channelID.Cmp(chID) {
+		t.Errorf("The channel IDs do not match %s vs %s",
+			dummy.channelID, chID)
+	}
+
+	if !dummy.messageID.Equals(umi.GetMessageID()) {
+		t.Errorf("The message IDs do not match %s vs %s",
+			dummy.messageID, umi.GetMessageID())
+	}
+
+	if dummy.messageType != mt {
+		t.Errorf("The message types do not match %s vs %s",
+			dummy.messageType, mt)
+	}
+
+	if dummy.nickname != umi.channelMessage.Nickname {
+		t.Errorf("The usernames do not match %s vs %s",
+			dummy.nickname, umi.channelMessage.Nickname)
+	}
+
+	if !bytes.Equal(dummy.content, umi.GetChannelMessage().Payload) {
+		t.Errorf("The payloads do not match %s vs %s",
+			dummy.content, umi.GetChannelMessage().Payload)
+	}
+
+	if !withinMutationWindow(r.Timestamps[states.QUEUED], dummy.timestamp) {
+		t.Errorf("The timestamps do not match %s vs %s",
+			dummy.timestamp, r.Timestamps[states.QUEUED])
+	}
+
+	if dummy.lease != time.Duration(umi.GetChannelMessage().Lease) {
+		t.Errorf("The messge lease durations do not match %s vs %s",
+			dummy.lease, time.Duration(umi.GetChannelMessage().Lease))
+	}
+
+	if dummy.round.ID != r.ID {
+		t.Errorf("The messge round does not match %s vs %s",
+			dummy.round.ID, r.ID)
+	}
+}
+
+func TestEvents_triggerEvents_noChannel(t *testing.T) {
+	me := &MockEvent{}
+
+	e := initEvents(me)
+
+	dummy := &dummyMessageTypeHandler{}
+
+	//skip handler registration
+	mt := MessageType(1)
+
+	//craft the input for the event
+	chID := &id.ID{}
+	chID[0] = 1
+
+	umi, _, _ := builtTestUMI(t, mt)
+
+	r := rounds.Round{ID: 420, Timestamps: make(map[states.Round]time.Time)}
+	r.Timestamps[states.QUEUED] = netTime.Now()
+
+	//call the trigger
+	_, err := e.triggerEvent(chID, umi, netTime.Now(), receptionID.EphemeralIdentity{}, r, Delivered)
+	if err != nil {
+		t.Fatalf(err.Error())
+	}
+
+	//check that the event was triggered
+	if dummy.triggered {
+		t.Errorf("The event was triggered when it is unregistered")
+	}
+}
+
+func TestEvents_triggerAdminEvents(t *testing.T) {
+	me := &MockEvent{}
+
+	e := initEvents(me)
+
+	dummy := &dummyMessageTypeHandler{}
+
+	//register the handler
+	mt := MessageType(42)
+	err := e.RegisterReceiveHandler(mt, dummy.dummyMessageTypeReceiveMessage)
+	if err != nil {
+		t.Fatalf("Error on registration, should not have happened: "+
+			"%+v", err)
+	}
+
+	//craft the input for the event
+	chID := &id.ID{}
+	chID[0] = 1
+
+	u, _, cm := builtTestUMI(t, mt)
+
+	r := rounds.Round{ID: 420, Timestamps: make(map[states.Round]time.Time)}
+	r.Timestamps[states.QUEUED] = netTime.Now()
+
+	msgID := cryptoChannel.MakeMessageID(u.userMessage.Message, chID)
+
+	//call the trigger
+	_, err = e.triggerAdminEvent(chID, cm, netTime.Now(), msgID, receptionID.EphemeralIdentity{}, r,
+		Delivered)
+	if err != nil {
+		t.Fatalf(err.Error())
+	}
+
+	//check that the event was triggered
+	if !dummy.triggered {
+		t.Errorf("The admin event was not triggered")
+	}
+
+	//check the data is stored in the dummy
+	if !dummy.channelID.Cmp(chID) {
+		t.Errorf("The channel IDs do not match %s vs %s",
+			dummy.channelID, chID)
+	}
+
+	if !dummy.messageID.Equals(msgID) {
+		t.Errorf("The message IDs do not match %s vs %s",
+			dummy.messageID, msgID)
+	}
+
+	if dummy.messageType != mt {
+		t.Errorf("The message types do not match %s vs %s",
+			dummy.messageType, mt)
+	}
+
+	if dummy.nickname != AdminUsername {
+		t.Errorf("The usernames do not match %s vs %s",
+			dummy.nickname, AdminUsername)
+	}
+
+	if !bytes.Equal(dummy.content, cm.Payload) {
+		t.Errorf("The payloads do not match %s vs %s",
+			dummy.content, cm.Payload)
+	}
+
+	if !withinMutationWindow(r.Timestamps[states.QUEUED], dummy.timestamp) {
+		t.Errorf("The timestamps do not match %s vs %s",
+			dummy.timestamp, r.Timestamps[states.QUEUED])
+	}
+
+	if dummy.lease != time.Duration(cm.Lease) {
+		t.Errorf("The messge lease durations do not match %s vs %s",
+			dummy.lease, time.Duration(cm.Lease))
+	}
+
+	if dummy.round.ID != r.ID {
+		t.Errorf("The messge round does not match %s vs %s",
+			dummy.round.ID, r.ID)
+	}
+}
+
+func TestEvents_triggerAdminEvents_noChannel(t *testing.T) {
+	me := &MockEvent{}
+
+	e := initEvents(me)
+
+	dummy := &dummyMessageTypeHandler{}
+
+	mt := MessageType(1)
+	//skip handler registration
+
+	//craft the input for the event
+	chID := &id.ID{}
+	chID[0] = 1
+
+	u, _, cm := builtTestUMI(t, mt)
+
+	r := rounds.Round{ID: 420, Timestamps: make(map[states.Round]time.Time)}
+	r.Timestamps[states.QUEUED] = netTime.Now()
+
+	msgID := cryptoChannel.MakeMessageID(u.userMessage.Message, chID)
+
+	//call the trigger
+	_, err := e.triggerAdminEvent(chID, cm, netTime.Now(), msgID, receptionID.EphemeralIdentity{}, r,
+		Delivered)
+	if err != nil {
+		t.Fatalf(err.Error())
+	}
+
+	//check that the event was triggered
+	if dummy.triggered {
+		t.Errorf("The admin event was triggered when unregistered")
+	}
+}
+
+func TestEvents_receiveTextMessage_Message(t *testing.T) {
+	me := &MockEvent{}
+
+	e := initEvents(me)
+
+	//craft the input for the event
+	chID := &id.ID{}
+	chID[0] = 1
+
+	textPayload := &CMIXChannelText{
+		Version:        0,
+		Text:           "They Don't Think It Be Like It Is, But It Do",
+		ReplyMessageID: nil,
+	}
+
+	textMarshaled, err := proto.Marshal(textPayload)
+	if err != nil {
+		t.Fatalf("failed to marshael the message proto: %+v", err)
+	}
+
+	msgID := cryptoChannel.MakeMessageID(textMarshaled, chID)
+
+	rng := rand.New(rand.NewSource(64))
+
+	pi, err := cryptoChannel.GenerateIdentity(rng)
+	if err != nil {
+		t.Fatalf(err.Error())
+	}
+
+	senderNickname := "Alice"
+	ts := netTime.Now()
+
+	lease := 69 * time.Minute
+
+	r := rounds.Round{ID: 420, Timestamps: make(map[states.Round]time.Time)}
+	r.Timestamps[states.QUEUED] = netTime.Now()
+
+	//call the handler
+	e.receiveTextMessage(chID, msgID, 0, senderNickname,
+		textMarshaled, pi.Identity, ts, lease, r, Delivered)
+
+	//check the results on the model
+	if !me.eventReceive.channelID.Cmp(chID) {
+		t.Errorf("Channel ID did not propogate correctly, %s vs %s",
+			me.eventReceive.channelID, chID)
+	}
+
+	if !me.eventReceive.messageID.Equals(msgID) {
+		t.Errorf("Message ID did not propogate correctly, %s vs %s",
+			me.eventReceive.messageID, msgID)
+	}
+
+	if !me.eventReceive.reactionTo.Equals(cryptoChannel.MessageID{}) {
+		t.Errorf("Reaction ID is not blank, %s",
+			me.eventReceive.reactionTo)
+	}
+
+	if me.eventReceive.nickname != senderNickname {
+		t.Errorf("SenderID propogate correctly, %s vs %s",
+			me.eventReceive.nickname, senderNickname)
+	}
+
+	if me.eventReceive.timestamp != ts {
+		t.Errorf("Message timestamp did not propogate correctly, %s vs %s",
+			me.eventReceive.timestamp, ts)
+	}
+
+	if me.eventReceive.lease != lease {
+		t.Errorf("Message lease did not propogate correctly, %s vs %s",
+			me.eventReceive.lease, lease)
+	}
+
+	if me.eventReceive.round.ID != r.ID {
+		t.Errorf("Message round did not propogate correctly, %d vs %d",
+			me.eventReceive.round.ID, r.ID)
+	}
+}
+
+func TestEvents_receiveTextMessage_Reply(t *testing.T) {
+	me := &MockEvent{}
+
+	e := initEvents(me)
+
+	//craft the input for the event
+	chID := &id.ID{}
+	chID[0] = 1
+
+	replyMsgId := cryptoChannel.MakeMessageID([]byte("blarg"), chID)
+
+	textPayload := &CMIXChannelText{
+		Version:        0,
+		Text:           "They Don't Think It Be Like It Is, But It Do",
+		ReplyMessageID: replyMsgId[:],
+	}
+
+	textMarshaled, err := proto.Marshal(textPayload)
+	if err != nil {
+		t.Fatalf("failed to marshael the message proto: %+v", err)
+	}
+
+	msgID := cryptoChannel.MakeMessageID(textMarshaled, chID)
+
+	senderUsername := "Alice"
+	ts := netTime.Now()
+
+	lease := 69 * time.Minute
+
+	r := rounds.Round{ID: 420, Timestamps: make(map[states.Round]time.Time)}
+	r.Timestamps[states.QUEUED] = netTime.Now()
+
+	rng := rand.New(rand.NewSource(64))
+
+	pi, err := cryptoChannel.GenerateIdentity(rng)
+	if err != nil {
+		t.Fatalf(err.Error())
+	}
+
+	//call the handler
+	e.receiveTextMessage(chID, msgID, Text, senderUsername,
+		textMarshaled, pi.Identity, ts, lease, r, Delivered)
+
+	//check the results on the model
+	if !me.eventReceive.channelID.Cmp(chID) {
+		t.Errorf("Channel ID did not propogate correctly, %s vs %s",
+			me.eventReceive.channelID, chID)
+	}
+
+	if !me.eventReceive.messageID.Equals(msgID) {
+		t.Errorf("Message ID did not propogate correctly, %s vs %s",
+			me.eventReceive.messageID, msgID)
+	}
+
+	if !me.eventReceive.reactionTo.Equals(replyMsgId) {
+		t.Errorf("Reaction ID is not equal to what was passed in, "+
+			"%s vs %s", me.eventReceive.reactionTo, replyMsgId)
+	}
+
+	if me.eventReceive.nickname != senderUsername {
+		t.Errorf("SenderID propogate correctly, %s vs %s",
+			me.eventReceive.nickname, senderUsername)
+	}
+
+	if me.eventReceive.timestamp != ts {
+		t.Errorf("Message timestamp did not propogate correctly, "+
+			"%s vs %s", me.eventReceive.timestamp, ts)
+	}
+
+	if me.eventReceive.lease != lease {
+		t.Errorf("Message lease did not propogate correctly, %s vs %s",
+			me.eventReceive.lease, lease)
+	}
+
+	if me.eventReceive.round.ID != r.ID {
+		t.Errorf("Message round did not propogate correctly, %d vs %d",
+			me.eventReceive.round.ID, r.ID)
+	}
+}
+
+func TestEvents_receiveTextMessage_Reply_BadReply(t *testing.T) {
+	me := &MockEvent{}
+
+	e := initEvents(me)
+
+	//craft the input for the event
+	chID := &id.ID{}
+	chID[0] = 1
+
+	replyMsgId := []byte("blarg")
+
+	textPayload := &CMIXChannelText{
+		Version:        0,
+		Text:           "They Don't Think It Be Like It Is, But It Do",
+		ReplyMessageID: replyMsgId[:],
+	}
+
+	textMarshaled, err := proto.Marshal(textPayload)
+	if err != nil {
+		t.Fatalf("failed to marshael the message proto: %+v", err)
+	}
+
+	msgID := cryptoChannel.MakeMessageID(textMarshaled, chID)
+
+	senderUsername := "Alice"
+	ts := netTime.Now()
+
+	lease := 69 * time.Minute
+
+	r := rounds.Round{ID: 420, Timestamps: make(map[states.Round]time.Time)}
+	r.Timestamps[states.QUEUED] = netTime.Now()
+
+	rng := rand.New(rand.NewSource(64))
+
+	pi, err := cryptoChannel.GenerateIdentity(rng)
+	if err != nil {
+		t.Fatalf(err.Error())
+	}
+
+	//call the handler
+	e.receiveTextMessage(chID, msgID, 0, senderUsername,
+		textMarshaled, pi.Identity, ts, lease, r, Delivered)
+
+	//check the results on the model
+	if !me.eventReceive.channelID.Cmp(chID) {
+		t.Errorf("Channel ID did not propogate correctly, %s vs %s",
+			me.eventReceive.channelID, chID)
+	}
+
+	if !me.eventReceive.messageID.Equals(msgID) {
+		t.Errorf("Message ID did not propogate correctly, %s vs %s",
+			me.eventReceive.messageID, msgID)
+	}
+
+	if !me.eventReceive.reactionTo.Equals(cryptoChannel.MessageID{}) {
+		t.Errorf("Reaction ID is not blank, %s",
+			me.eventReceive.reactionTo)
+	}
+
+	if me.eventReceive.nickname != senderUsername {
+		t.Errorf("SenderID propogate correctly, %s vs %s",
+			me.eventReceive.nickname, senderUsername)
+	}
+
+	if me.eventReceive.timestamp != ts {
+		t.Errorf("Message timestamp did not propogate correctly, "+
+			"%s vs %s", me.eventReceive.timestamp, ts)
+	}
+
+	if me.eventReceive.lease != lease {
+		t.Errorf("Message lease did not propogate correctly, %s vs %s",
+			me.eventReceive.lease, lease)
+	}
+
+	if me.eventReceive.round.ID != r.ID {
+		t.Errorf("Message round did not propogate correctly, %d vs %d",
+			me.eventReceive.round.ID, r.ID)
+	}
+}
+
+func TestEvents_receiveReaction(t *testing.T) {
+	me := &MockEvent{}
+
+	e := initEvents(me)
+
+	//craft the input for the event
+	chID := &id.ID{}
+	chID[0] = 1
+
+	replyMsgId := cryptoChannel.MakeMessageID([]byte("blarg"), chID)
+
+	textPayload := &CMIXChannelReaction{
+		Version:           0,
+		Reaction:          "🍆",
+		ReactionMessageID: replyMsgId[:],
+	}
+
+	textMarshaled, err := proto.Marshal(textPayload)
+	if err != nil {
+		t.Fatalf("failed to marshael the message proto: %+v", err)
+	}
+
+	msgID := cryptoChannel.MakeMessageID(textMarshaled, chID)
+
+	senderUsername := "Alice"
+	ts := netTime.Now()
+
+	lease := 69 * time.Minute
+
+	r := rounds.Round{ID: 420, Timestamps: make(map[states.Round]time.Time)}
+	r.Timestamps[states.QUEUED] = netTime.Now()
+
+	rng := rand.New(rand.NewSource(64))
+
+	pi, err := cryptoChannel.GenerateIdentity(rng)
+	if err != nil {
+		t.Fatalf(err.Error())
+	}
+
+	//call the handler
+	e.receiveReaction(chID, msgID, 0, senderUsername,
+		textMarshaled, pi.Identity, ts, lease, r, Delivered)
+
+	//check the results on the model
+	if !me.eventReceive.channelID.Cmp(chID) {
+		t.Errorf("Channel ID did not propogate correctly, %s vs %s",
+			me.eventReceive.channelID, chID)
+	}
+
+	if !me.eventReceive.messageID.Equals(msgID) {
+		t.Errorf("Message ID did not propogate correctly, %s vs %s",
+			me.eventReceive.messageID, msgID)
+	}
+
+	if !me.eventReceive.reactionTo.Equals(replyMsgId) {
+		t.Errorf("Reaction ID is not equal to what was passed in, "+
+			"%s vs %s", me.eventReceive.reactionTo, replyMsgId)
+	}
+
+	if me.eventReceive.nickname != senderUsername {
+		t.Errorf("SenderID propogate correctly, %s vs %s",
+			me.eventReceive.nickname, senderUsername)
+	}
+
+	if me.eventReceive.timestamp != ts {
+		t.Errorf("Message timestamp did not propogate correctly, "+
+			"%s vs %s", me.eventReceive.timestamp, ts)
+	}
+
+	if me.eventReceive.lease != lease {
+		t.Errorf("Message lease did not propogate correctly, %s vs %s",
+			me.eventReceive.lease, lease)
+	}
+
+	if me.eventReceive.round.ID != r.ID {
+		t.Errorf("Message round did not propogate correctly, %d vs %d",
+			me.eventReceive.round.ID, r.ID)
+	}
+}
+
+func TestEvents_receiveReaction_InvalidReactionMessageID(t *testing.T) {
+	me := &MockEvent{}
+
+	e := initEvents(me)
+
+	//craft the input for the event
+	chID := &id.ID{}
+	chID[0] = 1
+
+	replyMsgId := []byte("blarg")
+
+	textPayload := &CMIXChannelReaction{
+		Version:           0,
+		Reaction:          "🍆",
+		ReactionMessageID: replyMsgId[:],
+	}
+
+	textMarshaled, err := proto.Marshal(textPayload)
+	if err != nil {
+		t.Fatalf("failed to marshael the message proto: %+v", err)
+	}
+
+	msgID := cryptoChannel.MakeMessageID(textMarshaled, chID)
+
+	senderUsername := "Alice"
+	ts := netTime.Now()
+
+	lease := 69 * time.Minute
+
+	r := rounds.Round{ID: 420, Timestamps: make(map[states.Round]time.Time)}
+	r.Timestamps[states.QUEUED] = netTime.Now()
+
+	rng := rand.New(rand.NewSource(64))
+
+	pi, err := cryptoChannel.GenerateIdentity(rng)
+	if err != nil {
+		t.Fatalf(err.Error())
+	}
+
+	//call the handler
+	e.receiveReaction(chID, msgID, 0, senderUsername,
+		textMarshaled, pi.Identity, ts, lease, r, Delivered)
+
+	//check the results on the model
+	if me.eventReceive.channelID != nil {
+		t.Errorf("Channel ID did propogated correctly when the reaction " +
+			"is bad")
+	}
+
+	if me.eventReceive.messageID.Equals(msgID) {
+		t.Errorf("Message ID propogated correctly when the reaction is " +
+			"bad")
+	}
+
+	if !me.eventReceive.reactionTo.Equals(cryptoChannel.MessageID{}) {
+		t.Errorf("Reaction ID propogated correctly when the reaction " +
+			"is bad")
+	}
+
+	if me.eventReceive.nickname != "" {
+		t.Errorf("SenderID propogated correctly when the reaction " +
+			"is bad")
+	}
+
+	if me.eventReceive.lease != 0 {
+		t.Errorf("Message lease propogated correctly when the " +
+			"reaction is bad")
+	}
+}
+
+func TestEvents_receiveReaction_InvalidReactionContent(t *testing.T) {
+	me := &MockEvent{}
+
+	e := initEvents(me)
+
+	//craft the input for the event
+	chID := &id.ID{}
+	chID[0] = 1
+
+	replyMsgId := cryptoChannel.MakeMessageID([]byte("blarg"), chID)
+
+	textPayload := &CMIXChannelReaction{
+		Version:           0,
+		Reaction:          "I'm not a reaction",
+		ReactionMessageID: replyMsgId[:],
+	}
+
+	textMarshaled, err := proto.Marshal(textPayload)
+	if err != nil {
+		t.Fatalf("failed to marshael the message proto: %+v", err)
+	}
+
+	msgID := cryptoChannel.MakeMessageID(textMarshaled, chID)
+
+	senderUsername := "Alice"
+	ts := netTime.Now()
+
+	lease := 69 * time.Minute
+
+	r := rounds.Round{ID: 420, Timestamps: make(map[states.Round]time.Time)}
+	r.Timestamps[states.QUEUED] = netTime.Now()
+
+	rng := rand.New(rand.NewSource(64))
+
+	pi, err := cryptoChannel.GenerateIdentity(rng)
+	if err != nil {
+		t.Fatalf(err.Error())
+	}
+	//call the handler
+	e.receiveReaction(chID, msgID, 0, senderUsername,
+		textMarshaled, pi.Identity, ts, lease, r, Delivered)
+
+	//check the results on the model
+	if me.eventReceive.channelID != nil {
+		t.Errorf("Channel ID did propogated correctly when the reaction " +
+			"is bad")
+	}
+
+	if me.eventReceive.messageID.Equals(msgID) {
+		t.Errorf("Message ID propogated correctly when the reaction is " +
+			"bad")
+	}
+
+	if !me.eventReceive.reactionTo.Equals(cryptoChannel.MessageID{}) {
+		t.Errorf("Reaction ID propogated correctly when the reaction " +
+			"is bad")
+	}
+
+	if me.eventReceive.nickname != "" {
+		t.Errorf("SenderID propogated correctly when the reaction " +
+			"is bad")
+	}
+
+	if me.eventReceive.lease != 0 {
+		t.Errorf("Message lease propogated correctly when the " +
+			"reaction is bad")
+	}
+}
+
+func getFuncName(i interface{}) string {
+	return runtime.FuncForPC(reflect.ValueOf(i).Pointer()).Name()
+}
diff --git a/channels/identityStore.go b/channels/identityStore.go
new file mode 100644
index 0000000000000000000000000000000000000000..2432a86c8ee10449502319ae443e32a88c74a908
--- /dev/null
+++ b/channels/identityStore.go
@@ -0,0 +1,31 @@
+package channels
+
+import (
+	"gitlab.com/elixxir/client/storage/versioned"
+	cryptoChannel "gitlab.com/elixxir/crypto/channel"
+	"gitlab.com/xx_network/primitives/netTime"
+)
+
+const (
+	identityStoreStorageKey     = "identityStoreStorageKey"
+	identityStoreStorageVersion = 0
+)
+
+func storeIdentity(kv *versioned.KV, ident cryptoChannel.PrivateIdentity) error {
+	data := ident.Marshal()
+	obj := &versioned.Object{
+		Version:   identityStoreStorageVersion,
+		Timestamp: netTime.Now(),
+		Data:      data,
+	}
+
+	return kv.Set(identityStoreStorageKey, obj)
+}
+
+func loadIdentity(kv *versioned.KV) (cryptoChannel.PrivateIdentity, error) {
+	obj, err := kv.Get(identityStoreStorageKey, identityStoreStorageVersion)
+	if err != nil {
+		return cryptoChannel.PrivateIdentity{}, err
+	}
+	return cryptoChannel.UnmarshalPrivateIdentity(obj.Data)
+}
diff --git a/channels/identityStore_test.go b/channels/identityStore_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..ec2d72f9b90d77accb42d757682fa83f333689f2
--- /dev/null
+++ b/channels/identityStore_test.go
@@ -0,0 +1,46 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file                                                               //
+////////////////////////////////////////////////////////////////////////////////
+
+package channels
+
+import (
+	"bytes"
+	"encoding/base64"
+	"gitlab.com/elixxir/client/storage/versioned"
+	cryptoChannel "gitlab.com/elixxir/crypto/channel"
+	"gitlab.com/elixxir/ekv"
+	"gitlab.com/xx_network/crypto/csprng"
+	"testing"
+)
+
+func TestStoreLoadIdentity(t *testing.T) {
+	rng := &csprng.SystemRNG{}
+	privIdentity, err := cryptoChannel.GenerateIdentity(rng)
+	if err != nil {
+		t.Fatalf("GenerateIdentity error: %+v", err)
+	}
+
+	kv := versioned.NewKV(ekv.MakeMemstore())
+	err = storeIdentity(kv, privIdentity)
+	if err != nil {
+		t.Fatalf("storeIdentity error: %+v", err)
+	}
+
+	loadedIdentity, err := loadIdentity(kv)
+	if err != nil {
+		t.Fatalf("loadIdentity error: %+v", err)
+	}
+
+	if !bytes.Equal(loadedIdentity.Marshal(), privIdentity.Marshal()) {
+		t.Fatalf("Failed to load private identity."+
+			"\nExpected: %s"+
+			"\nReceived: %s",
+			base64.StdEncoding.EncodeToString(privIdentity.Marshal()),
+			base64.StdEncoding.EncodeToString(loadedIdentity.Marshal()))
+	}
+
+}
\ No newline at end of file
diff --git a/channels/interface.go b/channels/interface.go
new file mode 100644
index 0000000000000000000000000000000000000000..1d1874693d0aa80f4a5a1810b790436d2da58240
--- /dev/null
+++ b/channels/interface.go
@@ -0,0 +1,131 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file                                                               //
+////////////////////////////////////////////////////////////////////////////////
+
+package channels
+
+import (
+	"gitlab.com/elixxir/client/cmix"
+	"gitlab.com/elixxir/client/cmix/rounds"
+	cryptoBroadcast "gitlab.com/elixxir/crypto/broadcast"
+	cryptoChannel "gitlab.com/elixxir/crypto/channel"
+	"gitlab.com/elixxir/crypto/rsa"
+	"gitlab.com/xx_network/primitives/id"
+	"gitlab.com/xx_network/primitives/id/ephemeral"
+	"math"
+	"time"
+)
+
+// ValidForever is used as a validUntil lease when sending to denote the
+// message or operation never expires. Note: A message relay must be
+// present to enforce this otherwise things expire after 3 weeks due to
+// network retention.
+var ValidForever = time.Duration(math.MaxInt64)
+
+type Manager interface {
+
+	// GetIdentity returns the public identity associated with this channel manager
+	GetIdentity() cryptoChannel.Identity
+
+	// GetStorageTag returns the tag at which this manager is store for loading
+	// it is derived from the public key
+	GetStorageTag() string
+
+	// JoinChannel joins the given channel. It will fail if the channel has
+	// already been joined.
+	JoinChannel(channel *cryptoBroadcast.Channel) error
+
+	// LeaveChannel leaves the given channel. It will return an error if the
+	// channel was not previously joined.
+	LeaveChannel(channelID *id.ID) error
+
+	// SendGeneric is used to send a raw message over a channel. In general, it
+	// should be wrapped in a function which defines the wire protocol
+	// If the final message, before being sent over the wire, is too long, this will
+	// return an error. Due to the underlying encoding using compression, it isn't
+	// possible to define the largest payload that can be sent, but
+	// it will always be possible to send a payload of 802 bytes at minimum
+	// Them meaning of validUntil depends on the use case.
+	SendGeneric(channelID *id.ID, messageType MessageType,
+		msg []byte, validUntil time.Duration, params cmix.CMIXParams) (
+		cryptoChannel.MessageID, rounds.Round, ephemeral.Id, error)
+
+	// SendAdminGeneric is used to send a raw message over a channel encrypted
+	// with admin keys, identifying it as sent by the admin. In general, it
+	// should be wrapped in a function which defines the wire protocol
+	// If the final message, before being sent over the wire, is too long, this will
+	// return an error. The message must be at most 510 bytes long.
+	SendAdminGeneric(privKey rsa.PrivateKey, channelID *id.ID,
+		messageType MessageType, msg []byte, validUntil time.Duration,
+		params cmix.CMIXParams) (cryptoChannel.MessageID, rounds.Round,
+		ephemeral.Id, error)
+
+	// SendMessage is used to send a formatted message over a channel.
+	// Due to the underlying encoding using compression, it isn't
+	// possible to define the largest payload that can be sent, but
+	// it will always be possible to send a payload of 798 bytes at minimum
+	// The message will auto delete validUntil after the round it is sent in,
+	// lasting forever if ValidForever is used
+	SendMessage(channelID *id.ID, msg string, validUntil time.Duration,
+		params cmix.CMIXParams) (
+		cryptoChannel.MessageID, rounds.Round, ephemeral.Id, error)
+
+	// SendReply is used to send a formatted message over a channel.
+	// Due to the underlying encoding using compression, it isn't
+	// possible to define the largest payload that can be sent, but
+	// it will always be possible to send a payload of 766 bytes at minimum.
+	// If the message ID the reply is sent to doesnt exist, the other side will
+	// post the message as a normal message and not a reply.
+	// The message will auto delete validUntil after the round it is sent in,
+	// lasting forever if ValidForever is used
+	SendReply(channelID *id.ID, msg string, replyTo cryptoChannel.MessageID,
+		validUntil time.Duration, params cmix.CMIXParams) (
+		cryptoChannel.MessageID, rounds.Round, ephemeral.Id, error)
+
+	// SendReaction is used to send a reaction to a message over a channel. The
+	// reaction must be a single emoji with no other characters, and will be
+	// rejected otherwise.
+	//
+	// Clients will drop the reaction if they do not recognize the reactTo
+	// message.
+	SendReaction(channelID *id.ID, reaction string,
+		reactTo cryptoChannel.MessageID, params cmix.CMIXParams) (
+		cryptoChannel.MessageID, rounds.Round, ephemeral.Id, error)
+
+	// RegisterReceiveHandler is used to register handlers for non default
+	// message types so that they can be processed by modules. It is important
+	// that such modules sync up with the event model implementation.
+	//
+	// There can only be one handler per message type, and this will return an
+	// error on a multiple registration.
+	RegisterReceiveHandler(messageType MessageType,
+		listener MessageTypeReceiveMessage) error
+
+	// GetChannels returns the IDs of all channels that have been joined. Use
+	// getChannelsUnsafe if you already have taken the mux.
+	GetChannels() []*id.ID
+
+	// GetChannel returns the underlying cryptographic structure for a given
+	// channel.
+	GetChannel(chID *id.ID) (*cryptoBroadcast.Channel, error)
+
+	// ReplayChannel replays all messages from the channel within the network's
+	// memory (~3 weeks) over the event model. It does this by wiping the
+	// underlying state tracking for message pickup for the channel, causing all
+	// messages to be re-retrieved from the network
+	ReplayChannel(chID *id.ID) error
+
+	// SetNickname sets the nickname for a channel after checking that the
+	// nickname is valid using IsNicknameValid.
+	SetNickname(newNick string, ch *id.ID) error
+
+	// DeleteNickname removes the nickname for a given channel, using the
+	// codename for that channel instead.
+	DeleteNickname(ch *id.ID) error
+
+	// GetNickname returns the nickname for the given channel if it exists.
+	GetNickname(ch *id.ID) (nickname string, exists bool)
+}
diff --git a/channels/joinedChannel.go b/channels/joinedChannel.go
new file mode 100644
index 0000000000000000000000000000000000000000..1b6aa53e7f9b2539b983c418eab52368d7c129c0
--- /dev/null
+++ b/channels/joinedChannel.go
@@ -0,0 +1,271 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file                                                               //
+////////////////////////////////////////////////////////////////////////////////
+
+package channels
+
+import (
+	"encoding/json"
+	jww "github.com/spf13/jwalterweatherman"
+	"gitlab.com/elixxir/client/broadcast"
+	"gitlab.com/elixxir/client/storage/versioned"
+	cryptoBroadcast "gitlab.com/elixxir/crypto/broadcast"
+	"gitlab.com/elixxir/crypto/fastRNG"
+	"gitlab.com/xx_network/primitives/id"
+	"gitlab.com/xx_network/primitives/netTime"
+)
+
+const (
+	joinedChannelsVersion = 0
+	joinedChannelsKey     = "JoinedChannelsKey"
+	joinedChannelVersion  = 0
+	joinedChannelKey      = "JoinedChannelKey-"
+)
+
+// store stores the list of joined channels to disk while taking the read lock.
+func (m *manager) store() error {
+	m.mux.RLock()
+	defer m.mux.RUnlock()
+	return m.storeUnsafe()
+}
+
+// storeUnsafe stores the list of joined channels to disk without taking the
+// read lock. It must be used by another function that has already taken the
+// read lock.
+func (m *manager) storeUnsafe() error {
+	channelsList := m.getChannelsUnsafe()
+
+	data, err := json.Marshal(&channelsList)
+	if err != nil {
+		return err
+	}
+
+	obj := &versioned.Object{
+		Version:   joinedChannelsVersion,
+		Timestamp: netTime.Now(),
+		Data:      data,
+	}
+
+	return m.kv.Set(joinedChannelsKey, obj)
+}
+
+// loadChannels loads all currently joined channels from disk and registers them
+// for message reception.
+func (m *manager) loadChannels() {
+	obj, err := m.kv.Get(joinedChannelsKey, joinedChannelsVersion)
+	if !m.kv.Exists(err) {
+		m.channels = make(map[id.ID]*joinedChannel)
+		return
+	} else if err != nil {
+		jww.FATAL.Panicf("Failed to load channels: %+v", err)
+	}
+
+	chList := make([]*id.ID, 0, len(m.channels))
+	if err = json.Unmarshal(obj.Data, &chList); err != nil {
+		jww.FATAL.Panicf("Failed to load channels: %+v", err)
+	}
+
+	chMap := make(map[id.ID]*joinedChannel)
+
+	for i := range chList {
+		jc, err := loadJoinedChannel(
+			chList[i], m.kv, m.net, m.rng, m.events, m.broadcastMaker,
+			m.st.MessageReceive)
+		if err != nil {
+			jww.FATAL.Panicf("Failed to load channel %s: %+v", chList[i], err)
+		}
+		chMap[*chList[i]] = jc
+	}
+
+	m.channels = chMap
+}
+
+// addChannel adds a channel.
+func (m *manager) addChannel(channel *cryptoBroadcast.Channel) error {
+	m.mux.Lock()
+	defer m.mux.Unlock()
+	if _, exists := m.channels[*channel.ReceptionID]; exists {
+		return ChannelAlreadyExistsErr
+	}
+
+	b, err := m.broadcastMaker(channel, m.net, m.rng)
+	if err != nil {
+		return err
+	}
+
+	jc := &joinedChannel{b}
+	if err = jc.Store(m.kv); err != nil {
+		go b.Stop()
+		return err
+	}
+
+	m.channels[*jc.broadcast.Get().ReceptionID] = jc
+
+	if err = m.storeUnsafe(); err != nil {
+		go b.Stop()
+		return err
+	}
+
+	// Connect to listeners
+	err = b.RegisterListener((&userListener{
+		chID:      channel.ReceptionID,
+		trigger:   m.events.triggerEvent,
+		checkSent: m.st.MessageReceive,
+	}).Listen, broadcast.Symmetric)
+	if err != nil {
+		return err
+	}
+
+	err = b.RegisterListener((&adminListener{
+		chID:      channel.ReceptionID,
+		trigger:   m.events.triggerAdminEvent,
+		checkSent: m.st.MessageReceive,
+	}).Listen, broadcast.RSAToPublic)
+	if err != nil {
+		return err
+	}
+
+	return nil
+}
+
+// removeChannel deletes the channel with the given ID from the channel list and
+// stops it from broadcasting. Returns ChannelDoesNotExistsErr error if the
+// channel does not exist.
+func (m *manager) removeChannel(channelID *id.ID) error {
+	m.mux.Lock()
+	defer m.mux.Unlock()
+
+	ch, exists := m.channels[*channelID]
+	if !exists {
+		return ChannelDoesNotExistsErr
+	}
+
+	ch.broadcast.Stop()
+
+	delete(m.channels, *channelID)
+
+	err := m.storeUnsafe()
+	if err != nil {
+		return err
+	}
+
+	return ch.delete(m.kv)
+}
+
+// getChannel returns the given channel. Returns ChannelDoesNotExistsErr error
+// if the channel does not exist.
+func (m *manager) getChannel(channelID *id.ID) (*joinedChannel, error) {
+	m.mux.RLock()
+	defer m.mux.RUnlock()
+
+	jc, exists := m.channels[*channelID]
+	if !exists {
+		return nil, ChannelDoesNotExistsErr
+	}
+
+	return jc, nil
+}
+
+// getChannelsUnsafe returns the IDs of all channels that have been joined. This
+// function is unsafe because it does not take the mux; only use this function
+// when under a lock.
+func (m *manager) getChannelsUnsafe() []*id.ID {
+	list := make([]*id.ID, 0, len(m.channels))
+	for chID := range m.channels {
+		list = append(list, chID.DeepCopy())
+	}
+	return list
+}
+
+// joinedChannel holds channel info. It will expand to include admin data, so it
+// will be treated as a struct for now.
+type joinedChannel struct {
+	broadcast broadcast.Channel
+}
+
+// joinedChannelDisk is the representation of joinedChannel for storage.
+type joinedChannelDisk struct {
+	Broadcast *cryptoBroadcast.Channel
+}
+
+// Store writes the given channel to a unique storage location within the EKV.
+func (jc *joinedChannel) Store(kv *versioned.KV) error {
+	jcd := joinedChannelDisk{jc.broadcast.Get()}
+	data, err := json.Marshal(&jcd)
+	if err != nil {
+		return err
+	}
+
+	obj := &versioned.Object{
+		Version:   joinedChannelVersion,
+		Timestamp: netTime.Now(),
+		Data:      data,
+	}
+
+	return kv.Set(makeJoinedChannelKey(jc.broadcast.Get().ReceptionID), obj)
+}
+
+// loadJoinedChannel loads a given channel from ekv storage.
+func loadJoinedChannel(chId *id.ID, kv *versioned.KV, net broadcast.Client,
+	rngGen *fastRNG.StreamGenerator, e *events,
+	broadcastMaker broadcast.NewBroadcastChannelFunc, mr messageReceiveFunc) (*joinedChannel, error) {
+	obj, err := kv.Get(makeJoinedChannelKey(chId), joinedChannelVersion)
+	if err != nil {
+		return nil, err
+	}
+
+	jcd := &joinedChannelDisk{}
+
+	err = json.Unmarshal(obj.Data, jcd)
+	if err != nil {
+		return nil, err
+	}
+
+	b, err := initBroadcast(jcd.Broadcast, e, net, broadcastMaker, rngGen, mr)
+
+	jc := &joinedChannel{broadcast: b}
+	return jc, nil
+}
+
+// delete removes the channel from the kv.
+func (jc *joinedChannel) delete(kv *versioned.KV) error {
+	return kv.Delete(makeJoinedChannelKey(jc.broadcast.Get().ReceptionID),
+		joinedChannelVersion)
+}
+
+func makeJoinedChannelKey(chId *id.ID) string {
+	return joinedChannelKey + chId.HexEncode()
+}
+
+func initBroadcast(c *cryptoBroadcast.Channel,
+	e *events, net broadcast.Client,
+	broadcastMaker broadcast.NewBroadcastChannelFunc,
+	rngGen *fastRNG.StreamGenerator, mr messageReceiveFunc) (broadcast.Channel, error) {
+	b, err := broadcastMaker(c, net, rngGen)
+	if err != nil {
+		return nil, err
+	}
+
+	err = b.RegisterListener((&userListener{
+		chID:      c.ReceptionID,
+		trigger:   e.triggerEvent,
+		checkSent: mr,
+	}).Listen, broadcast.Symmetric)
+	if err != nil {
+		return nil, err
+	}
+
+	err = b.RegisterListener((&adminListener{
+		chID:      c.ReceptionID,
+		trigger:   e.triggerAdminEvent,
+		checkSent: mr,
+	}).Listen, broadcast.RSAToPublic)
+	if err != nil {
+		return nil, err
+	}
+
+	return b, nil
+}
diff --git a/channels/joinedChannel_test.go b/channels/joinedChannel_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..e3bee24de606711cc0a0cffcd24e6a6c9b42001d
--- /dev/null
+++ b/channels/joinedChannel_test.go
@@ -0,0 +1,643 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2020 xx network SEZC                                           //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file                                                               //
+////////////////////////////////////////////////////////////////////////////////
+
+package channels
+
+import (
+	"bytes"
+	"encoding/binary"
+	"gitlab.com/elixxir/client/broadcast"
+	clientCmix "gitlab.com/elixxir/client/cmix"
+	"gitlab.com/elixxir/client/cmix/message"
+	"gitlab.com/elixxir/client/cmix/rounds"
+	"gitlab.com/elixxir/client/storage/versioned"
+	cryptoBroadcast "gitlab.com/elixxir/crypto/broadcast"
+	cryptoChannel "gitlab.com/elixxir/crypto/channel"
+	"gitlab.com/elixxir/crypto/fastRNG"
+	"gitlab.com/elixxir/crypto/rsa"
+	"gitlab.com/elixxir/ekv"
+	"gitlab.com/xx_network/crypto/csprng"
+	"gitlab.com/xx_network/primitives/id"
+	"gitlab.com/xx_network/primitives/id/ephemeral"
+	"math/rand"
+	"reflect"
+	"sort"
+	"strconv"
+	"testing"
+	"time"
+)
+
+// Tests that manager.store stores the channel list in the ekv.
+func Test_manager_store(t *testing.T) {
+	rng := rand.New(rand.NewSource(64))
+
+	pi, err := cryptoChannel.GenerateIdentity(rng)
+	if err != nil {
+		t.Fatalf(err.Error())
+	}
+
+	mFace, err := NewManager(pi, versioned.NewKV(ekv.MakeMemstore()),
+		new(mockBroadcastClient),
+		fastRNG.NewStreamGenerator(1, 1, csprng.NewSystemRNG),
+		mockEventModelBuilder)
+	if err != nil {
+		t.Errorf(err.Error())
+	}
+
+	m := mFace.(*manager)
+
+	for i := 0; i < 10; i++ {
+		ch, _, err := newTestChannel("name_"+strconv.Itoa(i),
+			"description_"+strconv.Itoa(i), m.rng.GetStream())
+		if err != nil {
+			t.Errorf("Failed to create new channel %d: %+v", i, err)
+		}
+
+		b, err := broadcast.NewBroadcastChannel(ch, m.net, m.rng)
+		if err != nil {
+			t.Errorf("Failed to make new broadcast channel: %+v", err)
+		}
+
+		m.channels[*ch.ReceptionID] = &joinedChannel{b}
+	}
+
+	err = m.store()
+	if err != nil {
+		t.Errorf("Error storing channels: %+v", err)
+	}
+
+	_, err = m.kv.Get(joinedChannelsKey, joinedChannelsVersion)
+	if !ekv.Exists(err) {
+		t.Errorf("channel list not found in KV: %+v", err)
+	}
+}
+
+// Tests that the manager.loadChannels loads all the expected channels from the
+// ekv.
+func Test_manager_loadChannels(t *testing.T) {
+	rng := rand.New(rand.NewSource(64))
+
+	pi, err := cryptoChannel.GenerateIdentity(rng)
+	if err != nil {
+		t.Fatalf(err.Error())
+	}
+
+	mFace, err := NewManager(pi, versioned.NewKV(ekv.MakeMemstore()),
+		new(mockBroadcastClient),
+		fastRNG.NewStreamGenerator(1, 1, csprng.NewSystemRNG),
+		mockEventModelBuilder)
+	if err != nil {
+		t.Errorf(err.Error())
+	}
+
+	m := mFace.(*manager)
+
+	expected := make([]*joinedChannel, 10)
+
+	for i := range expected {
+		ch, _, err := newTestChannel("name_"+strconv.Itoa(i),
+			"description_"+strconv.Itoa(i), m.rng.GetStream())
+		if err != nil {
+			t.Errorf("Failed to create new channel %d: %+v", i, err)
+		}
+
+		b, err := broadcast.NewBroadcastChannel(ch, m.net, m.rng)
+		if err != nil {
+			t.Errorf("Failed to make new broadcast channel: %+v", err)
+		}
+
+		jc := &joinedChannel{b}
+		if err = jc.Store(m.kv); err != nil {
+			t.Errorf("Failed to store joinedChannel %d: %+v", i, err)
+		}
+
+		chID := *ch.ReceptionID
+		m.channels[chID] = jc
+		expected[i] = jc
+	}
+
+	err = m.store()
+	if err != nil {
+		t.Errorf("Error storing channels: %+v", err)
+	}
+
+	newManager := &manager{
+		channels:       make(map[id.ID]*joinedChannel),
+		kv:             m.kv,
+		net:            m.net,
+		rng:            m.rng,
+		broadcastMaker: m.broadcastMaker,
+	}
+
+	newManager.loadChannels()
+
+	for chID, loadedCh := range newManager.channels {
+		ch, exists := m.channels[chID]
+		if !exists {
+			t.Errorf("Channel %s does not exist.", &chID)
+		}
+
+		if !reflect.DeepEqual(ch.broadcast, loadedCh.broadcast) {
+			t.Errorf("Channel %s does not match loaded channel."+
+				"\nexpected: %+v\nreceived: %+v", &chID, ch.broadcast, loadedCh.broadcast)
+		}
+	}
+}
+
+// Tests that manager.addChannel adds the channel to the map and stores it in
+// the kv.
+func Test_manager_addChannel(t *testing.T) {
+	rng := rand.New(rand.NewSource(64))
+
+	pi, err := cryptoChannel.GenerateIdentity(rng)
+	if err != nil {
+		t.Fatalf(err.Error())
+	}
+
+	mFace, err := NewManager(pi, versioned.NewKV(ekv.MakeMemstore()),
+		new(mockBroadcastClient),
+		fastRNG.NewStreamGenerator(1, 1, csprng.NewSystemRNG),
+		mockEventModelBuilder)
+	if err != nil {
+		t.Errorf(err.Error())
+	}
+
+	m := mFace.(*manager)
+
+	ch, _, err := newTestChannel("name", "description", m.rng.GetStream())
+	if err != nil {
+		t.Errorf("Failed to create new channel: %+v", err)
+	}
+
+	err = m.addChannel(ch)
+	if err != nil {
+		t.Errorf("Failed to add new channel: %+v", err)
+	}
+
+	if _, exists := m.channels[*ch.ReceptionID]; !exists {
+		t.Errorf("Channel %s not added to channel map.", ch.Name)
+	}
+
+	_, err = m.kv.Get(makeJoinedChannelKey(ch.ReceptionID), joinedChannelVersion)
+	if err != nil {
+		t.Errorf("Failed to get joinedChannel from kv: %+v", err)
+	}
+
+	_, err = m.kv.Get(joinedChannelsKey, joinedChannelsVersion)
+	if err != nil {
+		t.Errorf("Failed to get channels from kv: %+v", err)
+	}
+}
+
+// Error path: tests that manager.addChannel returns ChannelAlreadyExistsErr
+// when the channel was already added.
+func Test_manager_addChannel_ChannelAlreadyExistsErr(t *testing.T) {
+	rng := rand.New(rand.NewSource(64))
+
+	pi, err := cryptoChannel.GenerateIdentity(rng)
+	if err != nil {
+		t.Fatalf(err.Error())
+	}
+
+	mFace, err := NewManager(pi, versioned.NewKV(ekv.MakeMemstore()),
+		new(mockBroadcastClient),
+		fastRNG.NewStreamGenerator(1, 1, csprng.NewSystemRNG),
+		mockEventModelBuilder)
+	if err != nil {
+		t.Errorf(err.Error())
+	}
+
+	m := mFace.(*manager)
+
+	ch, _, err := newTestChannel("name", "description", m.rng.GetStream())
+	if err != nil {
+		t.Errorf("Failed to create new channel: %+v", err)
+	}
+
+	err = m.addChannel(ch)
+	if err != nil {
+		t.Errorf("Failed to add new channel: %+v", err)
+	}
+
+	err = m.addChannel(ch)
+	if err == nil || err != ChannelAlreadyExistsErr {
+		t.Errorf("Received incorrect error when adding a channel that already "+
+			"exists.\nexpected: %s\nreceived: %+v", ChannelAlreadyExistsErr, err)
+	}
+}
+
+// Tests the manager.removeChannel deletes the channel from the map.
+func Test_manager_removeChannel(t *testing.T) {
+	rng := rand.New(rand.NewSource(64))
+
+	pi, err := cryptoChannel.GenerateIdentity(rng)
+	if err != nil {
+		t.Fatalf(err.Error())
+	}
+
+	mFace, err := NewManager(pi, versioned.NewKV(ekv.MakeMemstore()),
+		new(mockBroadcastClient),
+		fastRNG.NewStreamGenerator(1, 1, csprng.NewSystemRNG),
+		mockEventModelBuilder)
+	if err != nil {
+		t.Errorf(err.Error())
+	}
+
+	m := mFace.(*manager)
+
+	ch, _, err := newTestChannel("name", "description", m.rng.GetStream())
+	if err != nil {
+		t.Errorf("Failed to create new channel: %+v", err)
+	}
+
+	err = m.addChannel(ch)
+	if err != nil {
+		t.Errorf("Failed to add new channel: %+v", err)
+	}
+
+	err = m.removeChannel(ch.ReceptionID)
+	if err != nil {
+		t.Errorf("Error removing channel: %+v", err)
+	}
+
+	if _, exists := m.channels[*ch.ReceptionID]; exists {
+		t.Errorf("Channel %s was not remove from the channel map.", ch.Name)
+	}
+
+	_, err = m.kv.Get(makeJoinedChannelKey(ch.ReceptionID), joinedChannelVersion)
+	if ekv.Exists(err) {
+		t.Errorf("joinedChannel not removed from kv: %+v", err)
+	}
+}
+
+// Error path: tests that manager.removeChannel returns ChannelDoesNotExistsErr
+// when the channel was never added.
+func Test_manager_removeChannel_ChannelDoesNotExistsErr(t *testing.T) {
+	rng := rand.New(rand.NewSource(64))
+
+	pi, err := cryptoChannel.GenerateIdentity(rng)
+	if err != nil {
+		t.Fatalf(err.Error())
+	}
+
+	mFace, err := NewManager(pi, versioned.NewKV(ekv.MakeMemstore()),
+		new(mockBroadcastClient),
+		fastRNG.NewStreamGenerator(1, 1, csprng.NewSystemRNG),
+		mockEventModelBuilder)
+	if err != nil {
+		t.Errorf(err.Error())
+	}
+
+	m := mFace.(*manager)
+
+	ch, _, err := newTestChannel("name", "description", m.rng.GetStream())
+	if err != nil {
+		t.Errorf("Failed to create new channel: %+v", err)
+	}
+
+	err = m.removeChannel(ch.ReceptionID)
+	if err == nil || err != ChannelDoesNotExistsErr {
+		t.Errorf("Received incorrect error when removing a channel that does "+
+			"not exists.\nexpected: %s\nreceived: %+v",
+			ChannelDoesNotExistsErr, err)
+	}
+}
+
+// Tests the manager.getChannel returns the expected channel.
+func Test_manager_getChannel(t *testing.T) {
+	rng := rand.New(rand.NewSource(64))
+
+	pi, err := cryptoChannel.GenerateIdentity(rng)
+	if err != nil {
+		t.Fatalf(err.Error())
+	}
+
+	mFace, err := NewManager(pi, versioned.NewKV(ekv.MakeMemstore()),
+		new(mockBroadcastClient),
+		fastRNG.NewStreamGenerator(1, 1, csprng.NewSystemRNG),
+		mockEventModelBuilder)
+	if err != nil {
+		t.Errorf(err.Error())
+	}
+
+	m := mFace.(*manager)
+
+	ch, _, err := newTestChannel("name", "description", m.rng.GetStream())
+	if err != nil {
+		t.Errorf("Failed to create new channel: %+v", err)
+	}
+
+	err = m.addChannel(ch)
+	if err != nil {
+		t.Errorf("Failed to add new channel: %+v", err)
+	}
+
+	jc, err := m.getChannel(ch.ReceptionID)
+	if err != nil {
+		t.Errorf("Error getting channel: %+v", err)
+	}
+
+	if !reflect.DeepEqual(ch, jc.broadcast.Get()) {
+		t.Errorf("Received unexpected channel.\nexpected: %+v\nreceived: %+v",
+			ch, jc.broadcast.Get())
+	}
+}
+
+// Error path: tests that manager.getChannel returns ChannelDoesNotExistsErr
+// when the channel was never added.
+func Test_manager_getChannel_ChannelDoesNotExistsErr(t *testing.T) {
+	rng := rand.New(rand.NewSource(64))
+
+	pi, err := cryptoChannel.GenerateIdentity(rng)
+	if err != nil {
+		t.Fatalf(err.Error())
+	}
+
+	mFace, err := NewManager(pi, versioned.NewKV(ekv.MakeMemstore()),
+		new(mockBroadcastClient),
+		fastRNG.NewStreamGenerator(1, 1, csprng.NewSystemRNG),
+		mockEventModelBuilder)
+	if err != nil {
+		t.Errorf(err.Error())
+	}
+
+	m := mFace.(*manager)
+
+	ch, _, err := newTestChannel("name", "description", m.rng.GetStream())
+	if err != nil {
+		t.Errorf("Failed to create new channel: %+v", err)
+	}
+
+	_, err = m.getChannel(ch.ReceptionID)
+	if err == nil || err != ChannelDoesNotExistsErr {
+		t.Errorf("Received incorrect error when getting a channel that does "+
+			"not exists.\nexpected: %s\nreceived: %+v",
+			ChannelDoesNotExistsErr, err)
+	}
+}
+
+// Tests that manager.getChannels returns all the channels that were added to
+// the map.
+func Test_manager_getChannels(t *testing.T) {
+	rng := rand.New(rand.NewSource(64))
+
+	pi, err := cryptoChannel.GenerateIdentity(rng)
+	if err != nil {
+		t.Fatalf(err.Error())
+	}
+
+	mFace, err := NewManager(pi, versioned.NewKV(ekv.MakeMemstore()),
+		new(mockBroadcastClient),
+		fastRNG.NewStreamGenerator(1, 1, csprng.NewSystemRNG),
+		mockEventModelBuilder)
+	if err != nil {
+		t.Errorf(err.Error())
+	}
+
+	m := mFace.(*manager)
+
+	expected := make([]*id.ID, 10)
+
+	for i := range expected {
+		ch, _, err := newTestChannel("name_"+strconv.Itoa(i),
+			"description_"+strconv.Itoa(i), m.rng.GetStream())
+		if err != nil {
+			t.Errorf("Failed to create new channel %d: %+v", i, err)
+		}
+		expected[i] = ch.ReceptionID
+
+		err = m.addChannel(ch)
+		if err != nil {
+			t.Errorf("Failed to add new channel %d: %+v", i, err)
+		}
+	}
+
+	channelIDs := m.getChannelsUnsafe()
+
+	sort.SliceStable(expected, func(i, j int) bool {
+		return bytes.Compare(expected[i][:], expected[j][:]) == -1
+	})
+	sort.SliceStable(channelIDs, func(i, j int) bool {
+		return bytes.Compare(channelIDs[i][:], channelIDs[j][:]) == -1
+	})
+
+	if !reflect.DeepEqual(expected, channelIDs) {
+		t.Errorf("ID list does not match expected.\nexpected: %v\nreceived: %v",
+			expected, channelIDs)
+	}
+}
+
+// Tests that joinedChannel.Store saves the joinedChannel to the expected place
+// in the ekv.
+func Test_joinedChannel_Store(t *testing.T) {
+	kv := versioned.NewKV(ekv.MakeMemstore())
+	rng := fastRNG.NewStreamGenerator(1, 1, csprng.NewSystemRNG)
+	ch, _, err := newTestChannel("name", "description", rng.GetStream())
+	if err != nil {
+		t.Errorf("Failed to create new channel: %+v", err)
+	}
+
+	b, err := broadcast.NewBroadcastChannel(ch, new(mockBroadcastClient), rng)
+	if err != nil {
+		t.Errorf("Failed to create new broadcast channel: %+v", err)
+	}
+
+	jc := &joinedChannel{b}
+
+	err = jc.Store(kv)
+	if err != nil {
+		t.Errorf("Error storing joinedChannel: %+v", err)
+	}
+
+	_, err = kv.Get(makeJoinedChannelKey(ch.ReceptionID), joinedChannelVersion)
+	if !ekv.Exists(err) {
+		t.Errorf("joinedChannel not found in KV: %+v", err)
+	}
+}
+
+// Tests that loadJoinedChannel returns a joinedChannel from storage that
+// matches the original.
+func Test_loadJoinedChannel(t *testing.T) {
+	rng := rand.New(rand.NewSource(64))
+
+	pi, err := cryptoChannel.GenerateIdentity(rng)
+	if err != nil {
+		t.Fatalf(err.Error())
+	}
+
+	mFace, err := NewManager(pi, versioned.NewKV(ekv.MakeMemstore()),
+		new(mockBroadcastClient),
+		fastRNG.NewStreamGenerator(1, 1, csprng.NewSystemRNG),
+		mockEventModelBuilder)
+	if err != nil {
+		t.Errorf(err.Error())
+	}
+
+	m := mFace.(*manager)
+
+	ch, _, err := newTestChannel("name", "description", m.rng.GetStream())
+	if err != nil {
+		t.Errorf("Failed to create new channel: %+v", err)
+	}
+
+	err = m.addChannel(ch)
+	if err != nil {
+		t.Errorf("Failed to add channel: %+v", err)
+	}
+
+	loadedJc, err := loadJoinedChannel(ch.ReceptionID, m.kv, m.net, m.rng,
+		m.events, m.broadcastMaker, func(messageID cryptoChannel.MessageID, r rounds.Round) bool {
+			return false
+		})
+	if err != nil {
+		t.Errorf("Failed to load joinedChannel: %+v", err)
+	}
+
+	if !reflect.DeepEqual(ch, loadedJc.broadcast.Get()) {
+		t.Errorf("Loaded joinedChannel does not match original."+
+			"\nexpected: %+v\nreceived: %+v", ch, loadedJc.broadcast.Get())
+	}
+}
+
+// Tests that joinedChannel.delete deletes the stored joinedChannel from the
+// ekv.
+func Test_joinedChannel_delete(t *testing.T) {
+	kv := versioned.NewKV(ekv.MakeMemstore())
+	rng := fastRNG.NewStreamGenerator(1, 1, csprng.NewSystemRNG)
+	ch, _, err := newTestChannel("name", "description", rng.GetStream())
+	if err != nil {
+		t.Errorf("Failed to create new channel: %+v", err)
+	}
+
+	b, err := broadcast.NewBroadcastChannel(ch, new(mockBroadcastClient), rng)
+	if err != nil {
+		t.Errorf("Failed to create new broadcast channel: %+v", err)
+	}
+
+	jc := &joinedChannel{b}
+
+	err = jc.Store(kv)
+	if err != nil {
+		t.Errorf("Error storing joinedChannel: %+v", err)
+	}
+
+	err = jc.delete(kv)
+	if err != nil {
+		t.Errorf("Error deleting joinedChannel: %+v", err)
+	}
+
+	_, err = kv.Get(makeJoinedChannelKey(ch.ReceptionID), joinedChannelVersion)
+	if ekv.Exists(err) {
+		t.Errorf("joinedChannel found in KV: %+v", err)
+	}
+}
+
+// Consistency test of makeJoinedChannelKey.
+func Test_makeJoinedChannelKey_Consistency(t *testing.T) {
+	values := map[*id.ID]string{
+		id.NewIdFromUInt(0, id.User, t): "JoinedChannelKey-0x0000000000000000000000000000000000000000000000000000000000000000",
+		id.NewIdFromUInt(1, id.User, t): "JoinedChannelKey-0x0000000000000001000000000000000000000000000000000000000000000000",
+		id.NewIdFromUInt(2, id.User, t): "JoinedChannelKey-0x0000000000000002000000000000000000000000000000000000000000000000",
+		id.NewIdFromUInt(3, id.User, t): "JoinedChannelKey-0x0000000000000003000000000000000000000000000000000000000000000000",
+		id.NewIdFromUInt(4, id.User, t): "JoinedChannelKey-0x0000000000000004000000000000000000000000000000000000000000000000",
+		id.NewIdFromUInt(5, id.User, t): "JoinedChannelKey-0x0000000000000005000000000000000000000000000000000000000000000000",
+		id.NewIdFromUInt(6, id.User, t): "JoinedChannelKey-0x0000000000000006000000000000000000000000000000000000000000000000",
+		id.NewIdFromUInt(7, id.User, t): "JoinedChannelKey-0x0000000000000007000000000000000000000000000000000000000000000000",
+		id.NewIdFromUInt(8, id.User, t): "JoinedChannelKey-0x0000000000000008000000000000000000000000000000000000000000000000",
+		id.NewIdFromUInt(9, id.User, t): "JoinedChannelKey-0x0000000000000009000000000000000000000000000000000000000000000000",
+	}
+
+	for chID, expected := range values {
+		key := makeJoinedChannelKey(chID)
+
+		if expected != key {
+			t.Errorf("Unexpected key for ID %d.\nexpected: %s\nreceived: %s",
+				binary.BigEndian.Uint64(chID[:8]), expected, key)
+		}
+	}
+
+}
+
+// newTestChannel creates a new cryptoBroadcast.Channel in the same way that
+// cryptoBroadcast.NewChannel does but with a smaller RSA key and salt to make
+// tests run quicker.
+func newTestChannel(name, description string, rng csprng.Source) (
+	*cryptoBroadcast.Channel, rsa.PrivateKey, error) {
+	c, pk, err := cryptoBroadcast.NewChannelVariableKeyUnsafe(name, description, 1000, 512, rng)
+	return c, pk, err
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Mock Broadcast Client                                                      //
+////////////////////////////////////////////////////////////////////////////////
+
+// mockBroadcastClient adheres to the broadcast.Client interface.
+type mockBroadcastClient struct{}
+
+func (m *mockBroadcastClient) GetMaxMessageLength() int { return 123 }
+
+func (m *mockBroadcastClient) SendWithAssembler(*id.ID,
+	clientCmix.MessageAssembler, clientCmix.CMIXParams) (
+	rounds.Round, ephemeral.Id, error) {
+	return rounds.Round{ID: id.Round(567)}, ephemeral.Id{}, nil
+}
+
+func (m *mockBroadcastClient) IsHealthy() bool                                       { return true }
+func (m *mockBroadcastClient) AddIdentity(*id.ID, time.Time, bool)                   {}
+func (m *mockBroadcastClient) AddService(*id.ID, message.Service, message.Processor) {}
+func (m *mockBroadcastClient) DeleteClientService(*id.ID)                            {}
+func (m *mockBroadcastClient) RemoveIdentity(*id.ID)                                 {}
+func (m *mockBroadcastClient) GetRoundResults(timeout time.Duration,
+	roundCallback clientCmix.RoundEventCallback, roundList ...id.Round) {
+}
+func (m *mockBroadcastClient) AddHealthCallback(f func(bool)) uint64 { return 0 }
+func (m *mockBroadcastClient) RemoveHealthCallback(uint64)           {}
+
+////////////////////////////////////////////////////////////////////////////////
+// Mock EventModel                                                            //
+////////////////////////////////////////////////////////////////////////////////
+
+func mockEventModelBuilder(string) (EventModel, error) {
+	return &mockEventModel{}, nil
+}
+
+// mockEventModel adheres to the EventModel interface.
+type mockEventModel struct {
+	joinedCh *cryptoBroadcast.Channel
+	leftCh   *id.ID
+}
+
+func (m *mockEventModel) UpdateSentStatus(uuid uint64, messageID cryptoChannel.MessageID,
+	timestamp time.Time, round rounds.Round, status SentStatus) {
+	//TODO implement me
+	panic("implement me")
+}
+
+func (m *mockEventModel) JoinChannel(c *cryptoBroadcast.Channel) {
+	m.joinedCh = c
+}
+func (m *mockEventModel) LeaveChannel(c *id.ID) {
+	m.leftCh = c
+}
+func (m *mockEventModel) ReceiveMessage(channelID *id.ID, messageID cryptoChannel.MessageID,
+	nickname, text string, identity cryptoChannel.Identity,
+	timestamp time.Time, lease time.Duration, round rounds.Round,
+	mType MessageType, status SentStatus) uint64 {
+	return 0
+}
+func (m *mockEventModel) ReceiveReply(channelID *id.ID, messageID cryptoChannel.MessageID,
+	reactionTo cryptoChannel.MessageID, nickname, text string,
+	identity cryptoChannel.Identity, timestamp time.Time,
+	lease time.Duration, round rounds.Round, mType MessageType, status SentStatus) uint64 {
+	return 0
+}
+func (m *mockEventModel) ReceiveReaction(channelID *id.ID, messageID cryptoChannel.MessageID,
+	reactionTo cryptoChannel.MessageID, nickname, reaction string,
+	identity cryptoChannel.Identity, timestamp time.Time,
+	lease time.Duration, round rounds.Round, mType MessageType, status SentStatus) uint64 {
+	return 0
+}
diff --git a/channels/manager.go b/channels/manager.go
new file mode 100644
index 0000000000000000000000000000000000000000..f3de1b863b589c23f50f04e2f78f9f14c88924d0
--- /dev/null
+++ b/channels/manager.go
@@ -0,0 +1,243 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file                                                               //
+////////////////////////////////////////////////////////////////////////////////
+
+// Package channels provides a channels implementation on top of broadcast
+// which is capable of handing the user facing features of channels, including
+// replies, reactions, and eventually admin commands.
+package channels
+
+import (
+	"crypto/ed25519"
+	"encoding/base64"
+	"fmt"
+	"github.com/pkg/errors"
+	jww "github.com/spf13/jwalterweatherman"
+	"gitlab.com/elixxir/client/broadcast"
+	"gitlab.com/elixxir/client/cmix"
+	"gitlab.com/elixxir/client/cmix/message"
+	"gitlab.com/elixxir/client/cmix/rounds"
+	"gitlab.com/elixxir/client/storage/versioned"
+	cryptoBroadcast "gitlab.com/elixxir/crypto/broadcast"
+	cryptoChannel "gitlab.com/elixxir/crypto/channel"
+	"gitlab.com/elixxir/crypto/fastRNG"
+	"gitlab.com/xx_network/primitives/id"
+	"gitlab.com/xx_network/primitives/id/ephemeral"
+	"sync"
+	"time"
+)
+
+const storageTagFormat = "channelManagerStorageTag-%s"
+
+type manager struct {
+	// Sender Identity
+	me cryptoChannel.PrivateIdentity
+
+	// List of all channels
+	channels map[id.ID]*joinedChannel
+	mux      sync.RWMutex
+
+	// External references
+	kv  *versioned.KV
+	net Client
+	rng *fastRNG.StreamGenerator
+
+	// Events model
+	*events
+
+	// Nicknames
+	*nicknameManager
+
+	// Send tracker
+	st *sendTracker
+
+	// Makes the function that is used to create broadcasts be a pointer so that
+	// it can be replaced in tests
+	broadcastMaker broadcast.NewBroadcastChannelFunc
+}
+
+// Client contains the methods from cmix.Client that are required by the
+// [Manager].
+type Client interface {
+	GetMaxMessageLength() int
+	SendWithAssembler(recipient *id.ID, assembler cmix.MessageAssembler,
+		cmixParams cmix.CMIXParams) (rounds.Round, ephemeral.Id, error)
+	IsHealthy() bool
+	AddIdentity(id *id.ID, validUntil time.Time, persistent bool)
+	AddService(clientID *id.ID, newService message.Service,
+		response message.Processor)
+	DeleteClientService(clientID *id.ID)
+	RemoveIdentity(id *id.ID)
+	GetRoundResults(timeout time.Duration, roundCallback cmix.RoundEventCallback,
+		roundList ...id.Round)
+	AddHealthCallback(f func(bool)) uint64
+	RemoveHealthCallback(uint64)
+}
+
+// EventModelBuilder initialises the event model using the given path.
+type EventModelBuilder func(path string) (EventModel, error)
+
+// NewManager creates a new channel Manager from a [channel.PrivateIdentity]. It
+// prefixes the KV with a tag derived from the public key that can be retried
+// for reloading using [Manager.GetStorageTag].
+func NewManager(identity cryptoChannel.PrivateIdentity, kv *versioned.KV,
+	net Client, rng *fastRNG.StreamGenerator, modelBuilder EventModelBuilder) (
+	Manager, error) {
+
+	// Prefix the kv with the username so multiple can be run
+	storageTag := getStorageTag(identity.PubKey)
+	kv = kv.Prefix(storageTag)
+
+	if err := storeIdentity(kv, identity); err != nil {
+		return nil, err
+	}
+
+	model, err := modelBuilder(storageTag)
+	if err != nil {
+		return nil, errors.Errorf("Failed to build event model: %+v", err)
+	}
+
+	m := setupManager(identity, kv, net, rng, model)
+
+	return m, nil
+}
+
+// LoadManager restores a channel Manager from disk stored at the given storage
+// tag.
+func LoadManager(storageTag string, kv *versioned.KV, net Client,
+	rng *fastRNG.StreamGenerator, modelBuilder EventModelBuilder) (Manager, error) {
+
+	// Prefix the kv with the username so multiple can be run
+	kv = kv.Prefix(storageTag)
+
+	// Load the identity
+	identity, err := loadIdentity(kv)
+	if err != nil {
+		return nil, err
+	}
+
+	model, err := modelBuilder(storageTag)
+	if err != nil {
+		return nil, errors.Errorf("Failed to build event model: %+v", err)
+	}
+
+	m := setupManager(identity, kv, net, rng, model)
+
+	return m, nil
+}
+
+func setupManager(identity cryptoChannel.PrivateIdentity, kv *versioned.KV,
+	net Client, rng *fastRNG.StreamGenerator, model EventModel) *manager {
+
+	m := manager{
+		me:             identity,
+		kv:             kv,
+		net:            net,
+		rng:            rng,
+		broadcastMaker: broadcast.NewBroadcastChannel,
+	}
+
+	m.events = initEvents(model)
+
+	m.st = loadSendTracker(net, kv, m.events.triggerEvent,
+		m.events.triggerAdminEvent, model.UpdateSentStatus, rng)
+
+	m.loadChannels()
+
+	m.nicknameManager = loadOrNewNicknameManager(kv)
+
+	return &m
+}
+
+// JoinChannel joins the given channel. It will fail if the channel has already
+// been joined.
+func (m *manager) JoinChannel(channel *cryptoBroadcast.Channel) error {
+	err := m.addChannel(channel)
+	if err != nil {
+		return err
+	}
+
+	go m.events.model.JoinChannel(channel)
+
+	return nil
+}
+
+// LeaveChannel leaves the given channel. It will return an error if the channel
+// was not previously joined.
+func (m *manager) LeaveChannel(channelID *id.ID) error {
+	err := m.removeChannel(channelID)
+	if err != nil {
+		return err
+	}
+
+	go m.events.model.LeaveChannel(channelID)
+
+	return nil
+}
+
+// GetChannels returns the IDs of all channels that have been joined. Use
+// getChannelsUnsafe if you already have taken the mux.
+func (m *manager) GetChannels() []*id.ID {
+	m.mux.Lock()
+	defer m.mux.Unlock()
+	return m.getChannelsUnsafe()
+}
+
+// GetChannel returns the underlying cryptographic structure for a given channel.
+func (m *manager) GetChannel(chID *id.ID) (*cryptoBroadcast.Channel, error) {
+	jc, err := m.getChannel(chID)
+	if err != nil {
+		return nil, err
+	}
+	return jc.broadcast.Get(), nil
+}
+
+// ReplayChannel replays all messages from the channel within the network's
+// memory (~3 weeks) over the event model. It does this by wiping the
+// underlying state tracking for message pickup for the channel, causing all
+// messages to be re-retrieved from the network
+func (m *manager) ReplayChannel(chID *id.ID) error {
+	jww.INFO.Printf("Replaying messages on channel %s", chID)
+	m.mux.RLock()
+	defer m.mux.RUnlock()
+
+	jc, exists := m.channels[*chID]
+	if !exists {
+		return ChannelDoesNotExistsErr
+	}
+
+	c := jc.broadcast.Get()
+
+	// Stop the broadcast that will completely wipe it from the underlying cmix
+	// object
+	jc.broadcast.Stop()
+
+	// Re-instantiate the broadcast, re-registering it from scratch
+	b, err := initBroadcast(c, m.events, m.net, m.broadcastMaker, m.rng,
+		m.st.MessageReceive)
+	if err != nil {
+		return err
+	}
+	jc.broadcast = b
+
+	return nil
+
+}
+
+// GetStorageTag returns the tag at which this manager is store for loading
+// it is derived from the public key
+func (m *manager) GetStorageTag() string {
+	return getStorageTag(m.me.PubKey)
+}
+
+// GetIdentity returns the public identity associated with this channel manager
+func (m *manager) GetIdentity() cryptoChannel.Identity {
+	return m.me.Identity
+}
+
+func getStorageTag(pub ed25519.PublicKey) string {
+	return fmt.Sprintf(storageTagFormat, base64.StdEncoding.EncodeToString(pub))
+}
diff --git a/channels/manager_test.go b/channels/manager_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..6f07e2013d222e10d8c93bce7beeabbfd59ef8b1
--- /dev/null
+++ b/channels/manager_test.go
@@ -0,0 +1,222 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file                                                               //
+////////////////////////////////////////////////////////////////////////////////
+
+package channels
+
+import (
+	"fmt"
+	"gitlab.com/elixxir/client/broadcast"
+	"gitlab.com/elixxir/client/storage/versioned"
+	cryptoChannel "gitlab.com/elixxir/crypto/channel"
+	"gitlab.com/elixxir/crypto/fastRNG"
+	"gitlab.com/elixxir/ekv"
+	"gitlab.com/xx_network/crypto/csprng"
+	"gitlab.com/xx_network/primitives/id"
+	"math/rand"
+	"os"
+	"sync"
+	"testing"
+	"time"
+
+	jww "github.com/spf13/jwalterweatherman"
+)
+
+func TestMain(m *testing.M) {
+	// Many tests trigger WARN prints;, set the out threshold so the WARN prints
+	// can be seen in the logs
+	jww.SetStdoutThreshold(jww.LevelWarn)
+	os.Exit(m.Run())
+}
+
+func TestManager_JoinChannel(t *testing.T) {
+	rng := rand.New(rand.NewSource(64))
+
+	pi, err := cryptoChannel.GenerateIdentity(rng)
+	if err != nil {
+		t.Fatalf(err.Error())
+	}
+
+	mFace, err := NewManager(pi, versioned.NewKV(ekv.MakeMemstore()),
+		new(mockBroadcastClient),
+		fastRNG.NewStreamGenerator(1, 1, csprng.NewSystemRNG),
+		mockEventModelBuilder)
+	if err != nil {
+		t.Errorf(err.Error())
+	}
+
+	m := mFace.(*manager)
+	mem := m.events.model.(*mockEventModel)
+
+	ch, _, err := newTestChannel("name", "description", m.rng.GetStream())
+	if err != nil {
+		t.Errorf("Failed to create new channel: %+v", err)
+	}
+
+	err = m.JoinChannel(ch)
+	if err != nil {
+		t.Fatalf("Join Channel Errored: %s", err)
+	}
+
+	if _, exists := m.channels[*ch.ReceptionID]; !exists {
+		t.Errorf("Channel %s not added to channel map.", ch.Name)
+	}
+
+	//wait because the event model is called in another thread
+	time.Sleep(1 * time.Second)
+
+	if mem.joinedCh == nil {
+		t.Errorf("the channel join call was not propogated to the event " +
+			"model")
+	}
+}
+
+func TestManager_LeaveChannel(t *testing.T) {
+
+	rng := rand.New(rand.NewSource(64))
+
+	pi, err := cryptoChannel.GenerateIdentity(rng)
+	if err != nil {
+		t.Fatalf(err.Error())
+	}
+
+	mFace, err := NewManager(pi, versioned.NewKV(ekv.MakeMemstore()),
+		new(mockBroadcastClient),
+		fastRNG.NewStreamGenerator(1, 1, csprng.NewSystemRNG),
+		mockEventModelBuilder)
+	if err != nil {
+		t.Errorf(err.Error())
+	}
+
+	m := mFace.(*manager)
+	mem := m.events.model.(*mockEventModel)
+
+	ch, _, err := newTestChannel("name", "description", m.rng.GetStream())
+	if err != nil {
+		t.Errorf("Failed to create new channel: %+v", err)
+	}
+
+	err = m.JoinChannel(ch)
+	if err != nil {
+		t.Fatalf("Join Channel Errored: %s", err)
+	}
+
+	err = m.LeaveChannel(ch.ReceptionID)
+	if err != nil {
+		t.Fatalf("Leave Channel Errored: %s", err)
+	}
+
+	if _, exists := m.channels[*ch.ReceptionID]; exists {
+		t.Errorf("Channel %s still in map.", ch.Name)
+	}
+
+	//wait because the event model is called in another thread
+	time.Sleep(1 * time.Second)
+
+	if mem.leftCh == nil {
+		t.Errorf("the channel join call was not propogated to the event " +
+			"model")
+	}
+}
+
+func TestManager_GetChannels(t *testing.T) {
+	m := &manager{
+		channels: make(map[id.ID]*joinedChannel),
+		mux:      sync.RWMutex{},
+	}
+
+	rng := fastRNG.NewStreamGenerator(1, 1, csprng.NewSystemRNG)
+
+	numtests := 10
+
+	chList := make(map[id.ID]interface{})
+
+	for i := 0; i < 10; i++ {
+		name := fmt.Sprintf("testChannel %d", numtests)
+		s := rng.GetStream()
+		tc, _, err := newTestChannel(name, "blarg", s)
+		s.Close()
+		if err != nil {
+			t.Fatalf("failed to generate channel %s", name)
+		}
+		bc, err := broadcast.NewBroadcastChannel(tc, new(mockBroadcastClient), rng)
+		if err != nil {
+			t.Fatalf("failed to generate broadcast %s", name)
+		}
+		m.channels[*tc.ReceptionID] = &joinedChannel{broadcast: bc}
+		chList[*tc.ReceptionID] = nil
+	}
+
+	receivedChList := m.GetChannels()
+
+	for _, receivedCh := range receivedChList {
+		if _, exists := chList[*receivedCh]; !exists {
+			t.Errorf("Channel was not returned")
+		}
+	}
+}
+
+func TestManager_GetChannel(t *testing.T) {
+	m := &manager{
+		channels: make(map[id.ID]*joinedChannel),
+		mux:      sync.RWMutex{},
+	}
+
+	rng := fastRNG.NewStreamGenerator(1, 1, csprng.NewSystemRNG)
+
+	numtests := 10
+
+	chList := make([]*id.ID, 0, numtests)
+
+	for i := 0; i < 10; i++ {
+		name := fmt.Sprintf("testChannel %d", numtests)
+		s := rng.GetStream()
+		tc, _, err := newTestChannel(name, "blarg", s)
+		s.Close()
+		if err != nil {
+			t.Fatalf("failed to generate channel %s", name)
+		}
+		bc, err := broadcast.NewBroadcastChannel(tc, new(mockBroadcastClient), rng)
+		if err != nil {
+			t.Fatalf("failed to generate broadcast %s", name)
+		}
+		m.channels[*tc.ReceptionID] = &joinedChannel{broadcast: bc}
+		chList = append(chList, tc.ReceptionID)
+	}
+
+	for i, receivedCh := range chList {
+		ch, err := m.GetChannel(receivedCh)
+		if err != nil {
+			t.Errorf("Channel %d failed to be gotten", i)
+		} else if !ch.ReceptionID.Cmp(receivedCh) {
+			t.Errorf("Channel %d Get returned wrong channel", i)
+		}
+	}
+}
+
+func TestManager_GetChannel_BadChannel(t *testing.T) {
+	m := &manager{
+		channels: make(map[id.ID]*joinedChannel),
+		mux:      sync.RWMutex{},
+	}
+
+	numtests := 10
+
+	chList := make([]*id.ID, 0, numtests)
+
+	for i := 0; i < 10; i++ {
+		chId := &id.ID{}
+		chId[0] = byte(i)
+		chList = append(chList, chId)
+	}
+
+	for i, receivedCh := range chList {
+		_, err := m.GetChannel(receivedCh)
+		if err == nil {
+			t.Errorf("Channel %d returned when it doesnt exist", i)
+		}
+	}
+}
diff --git a/channels/messageTypes.go b/channels/messageTypes.go
new file mode 100644
index 0000000000000000000000000000000000000000..5ac6e2de3c914131655e484599171c5ac6114d90
--- /dev/null
+++ b/channels/messageTypes.go
@@ -0,0 +1,31 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file                                                               //
+////////////////////////////////////////////////////////////////////////////////
+
+package channels
+
+import "fmt"
+
+type MessageType uint32
+
+const (
+	Text      = MessageType(1)
+	AdminText = MessageType(2)
+	Reaction  = MessageType(3)
+)
+
+func (mt MessageType) String() string {
+	switch mt {
+	case Text:
+		return "Text"
+	case AdminText:
+		return "AdminText"
+	case Reaction:
+		return "Reaction"
+	default:
+		return fmt.Sprintf("Unknown messageType %d", mt)
+	}
+}
diff --git a/channels/messageTypes_test.go b/channels/messageTypes_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..170ebf0542de153bb23c2f2135c66ff597d633f7
--- /dev/null
+++ b/channels/messageTypes_test.go
@@ -0,0 +1,25 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file                                                               //
+////////////////////////////////////////////////////////////////////////////////
+
+package channels
+
+import "testing"
+
+func TestMessageType_String(t *testing.T) {
+	expected := []string{"Text", "AdminText", "Reaction", "Unknown messageType 4",
+		"Unknown messageType 5", "Unknown messageType 6", "Unknown messageType 7",
+		"Unknown messageType 8", "Unknown messageType 9",
+		"Unknown messageType 10"}
+
+	for i := 1; i <= 10; i++ {
+		mt := MessageType(i)
+		if mt.String() != expected[i-1] {
+			t.Errorf("Stringer failed on test %d, %s vs %s", i,
+				mt.String(), expected[i-1])
+		}
+	}
+}
diff --git a/channels/messages.go b/channels/messages.go
new file mode 100644
index 0000000000000000000000000000000000000000..0162c3c62f62c10c7c652d206e405e7a2383327b
--- /dev/null
+++ b/channels/messages.go
@@ -0,0 +1,75 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file                                                               //
+////////////////////////////////////////////////////////////////////////////////
+
+package channels
+
+import (
+	"github.com/golang/protobuf/proto"
+	"gitlab.com/elixxir/crypto/channel"
+	"gitlab.com/xx_network/primitives/id"
+)
+
+// userMessageInternal is the internal structure of a UserMessage protobuf.
+type userMessageInternal struct {
+	userMessage    *UserMessage
+	channelMessage *ChannelMessage
+	messageID      channel.MessageID
+}
+
+func newUserMessageInternal(ursMsg *UserMessage, chid *id.ID) (*userMessageInternal, error) {
+	chanMessage := &ChannelMessage{}
+	err := proto.Unmarshal(ursMsg.Message, chanMessage)
+	if err != nil {
+		return nil, err
+	}
+
+	channelMessage := chanMessage
+	return &userMessageInternal{
+		userMessage:    ursMsg,
+		channelMessage: channelMessage,
+		messageID:      channel.MakeMessageID(ursMsg.Message, chid),
+	}, nil
+}
+
+func unmarshalUserMessageInternal(usrMsg []byte, chid *id.ID) (*userMessageInternal, error) {
+
+	um := &UserMessage{}
+	if err := proto.Unmarshal(usrMsg, um); err != nil {
+		return nil, err
+	}
+
+	chanMessage := &ChannelMessage{}
+	err := proto.Unmarshal(um.Message, chanMessage)
+	if err != nil {
+		return nil, err
+	}
+
+	channelMessage := chanMessage
+
+	return &userMessageInternal{
+		userMessage:    um,
+		channelMessage: channelMessage,
+		messageID:      channel.MakeMessageID(um.Message, chid),
+	}, nil
+}
+
+// GetUserMessage retrieves the UserMessage within
+// userMessageInternal.
+func (umi *userMessageInternal) GetUserMessage() *UserMessage {
+	return umi.userMessage
+}
+
+// GetChannelMessage retrieves the ChannelMessage within
+// userMessageInternal.
+func (umi *userMessageInternal) GetChannelMessage() *ChannelMessage {
+	return umi.channelMessage
+}
+
+// GetMessageID retrieves the messageID for the message.
+func (umi *userMessageInternal) GetMessageID() channel.MessageID {
+	return umi.messageID
+}
diff --git a/channels/messages_test.go b/channels/messages_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..b5109bd30a535156edc2e80556b9db51d55313e4
--- /dev/null
+++ b/channels/messages_test.go
@@ -0,0 +1,166 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file                                                               //
+////////////////////////////////////////////////////////////////////////////////
+
+package channels
+
+import (
+	"github.com/golang/protobuf/proto"
+	"gitlab.com/elixxir/crypto/channel"
+	"gitlab.com/xx_network/primitives/id"
+	"reflect"
+	"testing"
+)
+
+func TestUnmarshalUserMessageInternal(t *testing.T) {
+	internal, usrMsg, _ := builtTestUMI(t, 7)
+
+	chID := &id.ID{}
+
+	usrMsgMarshaled, err := proto.Marshal(usrMsg)
+	if err != nil {
+		t.Fatalf("Failed to marshal user message: %+v", err)
+	}
+
+	umi, err := unmarshalUserMessageInternal(usrMsgMarshaled, chID)
+	if err != nil {
+		t.Fatalf("Failed to unmarshal user message: %+v", err)
+	}
+
+	if !umi.GetMessageID().Equals(internal.messageID) {
+		t.Errorf("Message IDs were changed in the unmarshal "+
+			"process, %s vs %s", internal.messageID, umi.GetMessageID())
+	}
+}
+
+func TestUnmarshalUserMessageInternal_BadUserMessage(t *testing.T) {
+	chID := &id.ID{}
+	_, err := unmarshalUserMessageInternal([]byte("Malformed"), chID)
+	if err == nil {
+		t.Fatalf("Error not returned on unmarshaling a bad user " +
+			"message")
+	}
+}
+
+func TestUnmarshalUserMessageInternal_BadChannelMessage(t *testing.T) {
+	_, usrMsg, _ := builtTestUMI(t, 7)
+
+	usrMsg.Message = []byte("Malformed")
+
+	chID := &id.ID{}
+
+	usrMsgMarshaled, err := proto.Marshal(usrMsg)
+	if err != nil {
+		t.Fatalf("Failed to marshal user message: %+v", err)
+	}
+
+	_, err = unmarshalUserMessageInternal(usrMsgMarshaled, chID)
+	if err == nil {
+		t.Fatalf("Error not returned on unmarshaling a user message " +
+			"with a bad channel message")
+	}
+}
+
+func TestNewUserMessageInternal_BadChannelMessage(t *testing.T) {
+	_, usrMsg, _ := builtTestUMI(t, 7)
+
+	usrMsg.Message = []byte("Malformed")
+
+	chID := &id.ID{}
+
+	_, err := newUserMessageInternal(usrMsg, chID)
+
+	if err == nil {
+		t.Fatalf("failed to produce error with malformed user message")
+	}
+}
+
+func TestUserMessageInternal_GetChannelMessage(t *testing.T) {
+	internal, _, channelMsg := builtTestUMI(t, 7)
+	received := internal.GetChannelMessage()
+
+	if !reflect.DeepEqual(received.Payload, channelMsg.Payload) ||
+		received.Lease != channelMsg.Lease ||
+		received.RoundID != channelMsg.RoundID ||
+		received.PayloadType != channelMsg.PayloadType {
+		t.Fatalf("GetChannelMessage did not return expected data."+
+			"\nExpected: %v"+
+			"\nReceived: %v", channelMsg, received)
+	}
+}
+
+func TestUserMessageInternal_GetUserMessage(t *testing.T) {
+	internal, usrMsg, _ := builtTestUMI(t, 7)
+	received := internal.GetUserMessage()
+
+	if !reflect.DeepEqual(received.Message, usrMsg.Message) ||
+		!reflect.DeepEqual(received.Signature, usrMsg.Signature) ||
+		!reflect.DeepEqual(received.ECCPublicKey, usrMsg.ECCPublicKey) {
+		t.Fatalf("GetUserMessage did not return expected data."+
+			"\nExpected: %v"+
+			"\nReceived: %v", usrMsg, received)
+	}
+}
+
+func TestUserMessageInternal_GetMessageID(t *testing.T) {
+	internal, usrMsg, _ := builtTestUMI(t, 7)
+	received := internal.GetMessageID()
+
+	chID := &id.ID{}
+
+	expected := channel.MakeMessageID(usrMsg.Message, chID)
+
+	if !reflect.DeepEqual(expected, received) {
+		t.Fatalf("GetMessageID did not return expected data."+
+			"\nExpected: %v"+
+			"\nReceived: %v", expected, received)
+	}
+}
+
+// Ensures the serialization hasn't changed, changing the message IDs. The
+// protocol is tolerant of this because only the sender seralizes, but
+// it would be good to know when this changes. If this test breaks, report it,
+// but it should be safe to update the expected
+func TestUserMessageInternal_GetMessageID_Consistency(t *testing.T) {
+	expected := "ChMsgID-LrGYLFCaPamZk44X+c/b08qtmJIorgNnoE68v1HYrf8="
+
+	internal, _, _ := builtTestUMI(t, 7)
+
+	received := internal.GetMessageID()
+
+	if expected != received.String() {
+		t.Fatalf("GetMessageID did not return expected data."+
+			"\nExpected: %v"+
+			"\nReceived: %v", expected, received)
+	}
+}
+
+func builtTestUMI(t *testing.T, mt MessageType) (*userMessageInternal, *UserMessage, *ChannelMessage) {
+	channelMsg := &ChannelMessage{
+		Lease:       69,
+		RoundID:     42,
+		PayloadType: uint32(mt),
+		Payload:     []byte("ban_badUSer"),
+		Nickname:    "paul",
+	}
+
+	serialized, err := proto.Marshal(channelMsg)
+	if err != nil {
+		t.Fatalf("Marshal error: %v", err)
+	}
+
+	usrMsg := &UserMessage{
+		Message:      serialized,
+		Signature:    []byte("sig2"),
+		ECCPublicKey: []byte("key"),
+	}
+
+	chID := &id.ID{}
+
+	internal, _ := newUserMessageInternal(usrMsg, chID)
+
+	return internal, usrMsg, channelMsg
+}
diff --git a/channels/mutateTimestamp.go b/channels/mutateTimestamp.go
new file mode 100644
index 0000000000000000000000000000000000000000..47c2bf1f02da14eaf829f37cb5b77970aaebf394
--- /dev/null
+++ b/channels/mutateTimestamp.go
@@ -0,0 +1,58 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file                                                               //
+////////////////////////////////////////////////////////////////////////////////
+
+package channels
+
+import (
+	"gitlab.com/elixxir/crypto/channel"
+	"gitlab.com/xx_network/crypto/large"
+	"time"
+)
+
+const (
+	// tenMsInNs is a prime close to one million to ensure patterns dont
+	// arise due to cofactors with the message ID when doing the modulo
+	tenMsInNs     = 10000019
+	halfTenMsInNs = tenMsInNs / 2
+)
+
+var tenMsInNsLargeInt = large.NewInt(tenMsInNs)
+
+// mutateTimestamp is used to modify the the timestamps on all messages in a
+// deterministic manner. This is because message ordering is done by timestamp
+// and the timestamps come from the rounds, which means multiple messages can
+// have the same timestamp due to being in the same round. The meaning of
+// conversations can change depending on order, so while no explicit order
+// can be discovered because to do so can leak potential ordering info for the
+// mix, choosing an arbitrary order and having all clients agree will at least
+// ensure that misunderstandings due to disagreements in order cannot occur
+//
+// In order to do this, this function mutates the timestamp of the round within
+// +/- 5ms seeded based upon the message ID.
+// It should be noted that this is only a reasonable assumption when the number
+// of messages in a channel isn't too much. For example, under these conditions
+// the birthday paradox of getting a collision if there are 10 messages for the
+// channel in the same round is ~4*10^-6, but the chance if there are 50
+// messages is 10^-4, and if the entire round is full of messages for the
+// channel (1000 messages), .0487.
+func mutateTimestamp(ts time.Time, msgID channel.MessageID) time.Time {
+
+	// Treat the message ID as a number and mod it by the number of ns in an ms
+	// to get an offset factor. Use a prime close to 1000000 to make sure there
+	// are no patterns in the output and reduce the chance of collision. While
+	// the fields do not align, so there is some bias towards some parts of the
+	// output field, that bias is too small to matter because log2(10000019) ~23
+	// while the input field is 256.
+	offsetLarge := large.NewIntFromBytes(msgID.Bytes())
+	offsetLarge.Mod(offsetLarge, tenMsInNsLargeInt)
+
+	// subtract half the field size so on average (across many runs) the message
+	// timestamps are not changed
+	offset := offsetLarge.Int64() - halfTenMsInNs
+
+	return time.Unix(0, ts.UnixNano()+offset)
+}
diff --git a/channels/mutateTimestamp_test.go b/channels/mutateTimestamp_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..120fd44156c2c1616a876d60db27725caebd6eaf
--- /dev/null
+++ b/channels/mutateTimestamp_test.go
@@ -0,0 +1,55 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file                                                               //
+////////////////////////////////////////////////////////////////////////////////
+
+package channels
+
+import (
+	"gitlab.com/xx_network/primitives/netTime"
+	"math/rand"
+	"testing"
+	"time"
+
+	"gitlab.com/elixxir/crypto/channel"
+)
+
+// withinMutationWindow is a utility test function to check if a mutated
+// timestamp is within the allowable window
+func withinMutationWindow(raw, mutated time.Time) bool {
+	lowerBound := raw.Add(-time.Duration(halfTenMsInNs))
+	upperBound := raw.Add(time.Duration(halfTenMsInNs))
+
+	return mutated.After(lowerBound) && mutated.Before(upperBound)
+}
+
+func abs(n int64) int64 {
+	if n < 0 {
+		return -n
+	}
+	return n
+}
+
+func TestMutateTimestampDeltaAverage(t *testing.T) {
+	samples := 10000
+	t1 := netTime.Now()
+	sum := int64(0)
+
+	rng := rand.New(rand.NewSource(netTime.Now().UnixNano()))
+
+	for i := 0; i < samples; i++ {
+		var msgID channel.MessageID
+		rng.Read(msgID[:])
+		t2 := mutateTimestamp(t1, msgID)
+		delta := t2.Sub(t1)
+		sum += abs(int64(delta))
+	}
+
+	avg := sum / int64(samples)
+	diff := abs(avg - 2502865)
+	if diff > 30000 {
+		t.Fatal()
+	}
+}
diff --git a/channels/nameService.go b/channels/nameService.go
new file mode 100644
index 0000000000000000000000000000000000000000..d77fa9414a4f0fe1d8a32fae130936187f2fcf92
--- /dev/null
+++ b/channels/nameService.go
@@ -0,0 +1,38 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file                                                               //
+////////////////////////////////////////////////////////////////////////////////
+
+package channels
+
+import (
+	"crypto/ed25519"
+	"time"
+)
+
+// NameService is an interface which encapsulates
+// the user identity channel tracking service.
+// NameService is currently unused
+type NameService interface {
+
+	// GetUsername returns the username.
+	GetUsername() string
+
+	// GetChannelValidationSignature returns the validation
+	// signature and the time it was signed.
+	GetChannelValidationSignature() ([]byte, time.Time)
+
+	// GetChannelPubkey returns the user's public key.
+	GetChannelPubkey() ed25519.PublicKey
+
+	// SignChannelMessage returns the signature of the
+	// given message.
+	SignChannelMessage(message []byte) (signature []byte, err error)
+
+	// ValidateChannelMessage validates that a received channel message's
+	// username lease is signed by the NameService
+	ValidateChannelMessage(username string, lease time.Time,
+		pubKey ed25519.PublicKey, authorIDSignature []byte) bool
+}
diff --git a/channels/nickname.go b/channels/nickname.go
new file mode 100644
index 0000000000000000000000000000000000000000..5116b597f754c09ce1b6bae06ec878c5192debfe
--- /dev/null
+++ b/channels/nickname.go
@@ -0,0 +1,146 @@
+package channels
+
+import (
+	"encoding/json"
+	"errors"
+	jww "github.com/spf13/jwalterweatherman"
+	"gitlab.com/elixxir/client/storage/versioned"
+	"gitlab.com/xx_network/primitives/id"
+	"gitlab.com/xx_network/primitives/netTime"
+	"sync"
+)
+
+const (
+	nicknameStoreStorageKey     = "nicknameStoreStorageKey"
+	nicknameStoreStorageVersion = 0
+)
+
+type nicknameManager struct {
+	byChannel map[id.ID]string
+
+	mux sync.RWMutex
+
+	kv *versioned.KV
+}
+
+// loadOrNewNicknameManager returns the stored nickname manager if there is
+// one or returns a new one
+func loadOrNewNicknameManager(kv *versioned.KV) *nicknameManager {
+	nm := &nicknameManager{
+		byChannel: make(map[id.ID]string),
+		kv:        kv,
+	}
+	err := nm.load()
+	if err != nil && nm.kv.Exists(err) {
+		jww.FATAL.Panicf("Failed to load nicknameManager: %+v", err)
+	}
+
+	return nm
+
+}
+
+// GetNickname returns the nickname for the given channel if it exists
+func (nm *nicknameManager) GetNickname(ch *id.ID) (
+	nickname string, exists bool) {
+	nm.mux.RLock()
+	defer nm.mux.RUnlock()
+
+	nickname, exists = nm.byChannel[*ch]
+	return
+}
+
+// SetNickname sets the nickname for a channel after checking that the nickname
+// is valid using IsNicknameValid
+func (nm *nicknameManager) SetNickname(newNick string, ch *id.ID) error {
+	nm.mux.Lock()
+	defer nm.mux.Unlock()
+
+	if err := IsNicknameValid(newNick); err != nil {
+		return err
+	}
+
+	nm.byChannel[*ch] = newNick
+	return nm.save()
+}
+
+// DeleteNickname removes the nickname for a given channel, using the codename
+// for that channel instead
+func (nm *nicknameManager) DeleteNickname(ch *id.ID) error {
+	nm.mux.Lock()
+	defer nm.mux.Unlock()
+
+	delete(nm.byChannel, *ch)
+
+	return nm.save()
+}
+
+// channelIDToNickname is a serialization structure. This is used by the save
+// and load functions to serialize the nicknameManager's byChannel map.
+type channelIDToNickname struct {
+	ChannelId id.ID
+	Nickname  string
+}
+
+// save stores the nickname manager to disk. The caller of this must
+// hold the mux.
+func (nm *nicknameManager) save() error {
+	list := make([]channelIDToNickname, 0)
+	for chId, nickname := range nm.byChannel {
+		list = append(list, channelIDToNickname{
+			ChannelId: chId,
+			Nickname:  nickname,
+		})
+	}
+
+	data, err := json.Marshal(list)
+	if err != nil {
+		return err
+	}
+	obj := &versioned.Object{
+		Version:   nicknameStoreStorageVersion,
+		Timestamp: netTime.Now(),
+		Data:      data,
+	}
+
+	return nm.kv.Set(nicknameStoreStorageKey, obj)
+}
+
+// load restores the nickname manager from disk.
+func (nm *nicknameManager) load() error {
+	obj, err := nm.kv.Get(nicknameStoreStorageKey, nicknameStoreStorageVersion)
+	if err != nil {
+		return err
+	}
+
+	list := make([]channelIDToNickname, 0)
+	err = json.Unmarshal(obj.Data, &list)
+	if err != nil {
+		return err
+	}
+
+	for i := range list {
+		current := list[i]
+		nm.byChannel[current.ChannelId] = current.Nickname
+	}
+
+	return nil
+}
+
+// IsNicknameValid checks if a nickname is valid
+//
+// rules
+//   - a nickname must not be longer than 24 characters
+//   - a nickname must not be shorter than 1 character
+// todo: add character filtering
+func IsNicknameValid(nick string) error {
+	runeNick := []rune(nick)
+	if len(runeNick) > 24 {
+		return errors.New("nicknames must be 24 characters in length or less")
+	}
+
+	if len(runeNick) < 1 {
+		return errors.New("nicknames must be at least 1 character in length")
+	}
+
+	return nil
+}
diff --git a/channels/nickname_test.go b/channels/nickname_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..cf535245f82bb1e4b5c4caf5ac0b65f6355b4653
--- /dev/null
+++ b/channels/nickname_test.go
@@ -0,0 +1,108 @@
+package channels
+
+import (
+	"gitlab.com/elixxir/client/storage/versioned"
+	"gitlab.com/elixxir/ekv"
+	"gitlab.com/xx_network/primitives/id"
+	"strconv"
+	"testing"
+)
+
+// Unit test. Tests that once you set a nickname with SetNickname, you can
+// retrieve the nickname using GetNickname.
+func TestNicknameManager_SetGetNickname(t *testing.T) {
+	kv := versioned.NewKV(ekv.MakeMemstore())
+	nm := loadOrNewNicknameManager(kv)
+
+	for i := 0; i < numTests; i++ {
+		chId := id.NewIdFromUInt(uint64(i), id.User, t)
+		nickname := "nickname#" + strconv.Itoa(i)
+		err := nm.SetNickname(nickname, chId)
+		if err != nil {
+			t.Fatalf("SetNickname error when setting %s: %+v", nickname, err)
+		}
+
+		received, _ := nm.GetNickname(chId)
+		if received != nickname {
+			t.Fatalf("GetNickname did not return expected values."+
+				"\nExpected: %s"+
+				"\nReceived: %s", nickname, received)
+		}
+	}
+}
+
+// Unit test. Tests that once you set a nickname with SetNickname, you can
+// retrieve the nickname using GetNickname after a reload.
+func TestNicknameManager_SetGetNickname_Reload(t *testing.T) {
+	kv := versioned.NewKV(ekv.MakeMemstore())
+	nm := loadOrNewNicknameManager(kv)
+
+	for i := 0; i < numTests; i++ {
+		chId := id.NewIdFromUInt(uint64(i), id.User, t)
+		nickname := "nickname#" + strconv.Itoa(i)
+		err := nm.SetNickname(nickname, chId)
+		if err != nil {
+			t.Fatalf("SetNickname error when setting %s: %+v", nickname, err)
+		}
+	}
+
+	nm2 := loadOrNewNicknameManager(kv)
+
+	for i := 0; i < numTests; i++ {
+		chId := id.NewIdFromUInt(uint64(i), id.User, t)
+		nick, exists := nm2.GetNickname(chId)
+		if !exists {
+			t.Fatalf("Nickname %d not found  ", i)
+		}
+		expected := "nickname#" + strconv.Itoa(i)
+		if nick != expected {
+			t.Fatalf("Nickname %d not found, expected: %s, received: %s ", i, expected, nick)
+		}
+	}
+}
+
+// Error case: Tests that nicknameManager.GetNickname returns a false boolean
+// if no nickname has been set with the channel ID.
+func TestNicknameManager_GetNickname_Error(t *testing.T) {
+	kv := versioned.NewKV(ekv.MakeMemstore())
+	nm := loadOrNewNicknameManager(kv)
+
+	for i := 0; i < numTests; i++ {
+		chId := id.NewIdFromUInt(uint64(i), id.User, t)
+		_, exists := nm.GetNickname(chId)
+		if exists {
+			t.Fatalf("GetNickname expected error case: " +
+				"This should not retrieve nicknames for channel IDs " +
+				"that are not set.")
+		}
+	}
+}
+
+// Unit test. Check that once you SetNickname and DeleteNickname,
+// GetNickname returns a false boolean.
+func TestNicknameManager_DeleteNickname(t *testing.T) {
+	kv := versioned.NewKV(ekv.MakeMemstore())
+	nm := loadOrNewNicknameManager(kv)
+
+	for i := 0; i < numTests; i++ {
+		chId := id.NewIdFromUInt(uint64(i), id.User, t)
+		nickname := "nickname#" + strconv.Itoa(i)
+		err := nm.SetNickname(nickname, chId)
+		if err != nil {
+			t.Fatalf("SetNickname error when setting %s: %+v", nickname, err)
+		}
+
+		err = nm.DeleteNickname(chId)
+		if err != nil {
+			t.Fatalf("DeleteNickname error: %+v", err)
+		}
+
+		_, exists := nm.GetNickname(chId)
+		if exists {
+			t.Fatalf("GetNickname expected error case: " +
+				"This should not retrieve nicknames for channel IDs " +
+				"that are not set.")
+		}
+	}
+
+}
diff --git a/channels/readme.md b/channels/readme.md
new file mode 100644
index 0000000000000000000000000000000000000000..9327e9635afd9c109054bf7b486d24c97a53c0bc
--- /dev/null
+++ b/channels/readme.md
@@ -0,0 +1,21 @@
+Channels provides a channels implementation on top of broadcast which is capable of handing the user facing features of
+channels, including replies, reactions, and eventually admin commands.
+
+on sending, data propagates as follows:
+Send function (Example: SendMessage) - > SendGeneric ->
+Broadcast.BroadcastWithAssembler -> cmix.SendWithAssembler
+
+on receiving messages propagate as follows:
+cmix message pickup (by service)- > broadcast.Processor ->
+userListener ->  events.triggerEvent ->
+messageTypeHandler (example: Text) ->
+eventModel (example: ReceiveMessage)
+
+on sendingAdmin, data propagates as follows:
+Send function - > SendAdminGeneric ->
+Broadcast.BroadcastAsymmetricWithAssembler -> cmix.SendWithAssembler
+
+on receiving admin messages propagate as follows:
+cmix message pickup (by service)- > broadcast.Processor -> adminListener ->
+events.triggerAdminEvent -> messageTypeHandler (example: Text) ->
+eventModel (example: ReceiveMessage)
\ No newline at end of file
diff --git a/channels/send.go b/channels/send.go
new file mode 100644
index 0000000000000000000000000000000000000000..7b46152bb07b801fcd23fcd649829065d4e654db
--- /dev/null
+++ b/channels/send.go
@@ -0,0 +1,287 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file                                                               //
+////////////////////////////////////////////////////////////////////////////////
+
+package channels
+
+import (
+	"crypto/ed25519"
+	"github.com/pkg/errors"
+	jww "github.com/spf13/jwalterweatherman"
+	"gitlab.com/elixxir/client/cmix"
+	"gitlab.com/elixxir/client/cmix/rounds"
+	cryptoChannel "gitlab.com/elixxir/crypto/channel"
+	"gitlab.com/elixxir/crypto/rsa"
+	"gitlab.com/xx_network/primitives/id"
+	"gitlab.com/xx_network/primitives/id/ephemeral"
+	"google.golang.org/protobuf/proto"
+	"time"
+)
+
+const (
+	cmixChannelTextVersion     = 0
+	cmixChannelReactionVersion = 0
+)
+
+// The size of the nonce used in the message ID.
+const messageNonceSize = 4
+
+// SendGeneric is used to send a raw message over a channel. In general, it
+// should be wrapped in a function which defines the wire protocol
+// If the final message, before being sent over the wire, is too long, this will
+// return an error. Due to the underlying encoding using compression, it isn't
+// possible to define the largest payload that can be sent, but
+// it will always be possible to send a payload of 802 bytes at minimum
+func (m *manager) SendGeneric(channelID *id.ID, messageType MessageType,
+	msg []byte, validUntil time.Duration, params cmix.CMIXParams) (
+	cryptoChannel.MessageID, rounds.Round, ephemeral.Id, error) {
+
+	//find the channel
+	ch, err := m.getChannel(channelID)
+	if err != nil {
+		return cryptoChannel.MessageID{}, rounds.Round{}, ephemeral.Id{}, err
+	}
+
+	nickname, _ := m.nicknameManager.GetNickname(channelID)
+
+	var msgId cryptoChannel.MessageID
+
+	chMsg := &ChannelMessage{
+		Lease:       validUntil.Nanoseconds(),
+		PayloadType: uint32(messageType),
+		Payload:     msg,
+		Nickname:    nickname,
+		Nonce:       make([]byte, messageNonceSize),
+	}
+
+	// Generate random nonce to be used for message ID generation. This makes it
+	// so two identical messages sent on the same round have different message IDs
+	rng := m.rng.GetStream()
+	n, err := rng.Read(chMsg.Nonce)
+	rng.Close()
+	if err != nil {
+		return cryptoChannel.MessageID{}, rounds.Round{}, ephemeral.Id{},
+			errors.Errorf("Failed to generate nonce: %+v", err)
+	} else if n != messageNonceSize {
+		return cryptoChannel.MessageID{}, rounds.Round{}, ephemeral.Id{},
+			errors.Errorf(
+				"Generated %d bytes for %-byte nonce", n, messageNonceSize)
+	}
+
+	usrMsg := &UserMessage{
+		ECCPublicKey: m.me.PubKey,
+	}
+
+	//Note: we are not checking check if message is too long before trying to
+	//find a round
+
+	//Build the function pointer that will build the message
+	assemble := func(rid id.Round) ([]byte, error) {
+
+		//Build the message
+		chMsg.RoundID = uint64(rid)
+
+		//Serialize the message
+		chMsgSerial, err := proto.Marshal(chMsg)
+		if err != nil {
+			return nil, err
+		}
+
+		//make the messageID
+		msgId = cryptoChannel.MakeMessageID(chMsgSerial, channelID)
+
+		//Sign the message
+		messageSig := ed25519.Sign(*m.me.Privkey, chMsgSerial)
+
+		usrMsg.Message = chMsgSerial
+		usrMsg.Signature = messageSig
+
+		//Serialize the user message
+		usrMsgSerial, err := proto.Marshal(usrMsg)
+		if err != nil {
+			return nil, err
+		}
+
+		return usrMsgSerial, nil
+	}
+
+	uuid, err := m.st.denotePendingSend(channelID, &userMessageInternal{
+		userMessage:    usrMsg,
+		channelMessage: chMsg,
+		messageID:      msgId,
+	})
+
+	r, ephid, err := ch.broadcast.BroadcastWithAssembler(assemble, params)
+	if err != nil {
+		errDenote := m.st.failedSend(uuid)
+		if errDenote != nil {
+			jww.ERROR.Printf("Failed to update for a failed send to "+
+				"%s: %+v", channelID, err)
+		}
+		return cryptoChannel.MessageID{}, rounds.Round{}, ephemeral.Id{}, err
+	}
+	err = m.st.send(uuid, msgId, r)
+	return msgId, r, ephid, err
+}
+
+// SendAdminGeneric is used to send a raw message over a channel encrypted
+// with admin keys, identifying it as sent by the admin. In general, it
+// should be wrapped in a function which defines the wire protocol
+// If the final message, before being sent over the wire, is too long, this will
+// return an error. The message must be at most 510 bytes long.
+func (m *manager) SendAdminGeneric(privKey rsa.PrivateKey, channelID *id.ID,
+	messageType MessageType, msg []byte, validUntil time.Duration,
+	params cmix.CMIXParams) (cryptoChannel.MessageID, rounds.Round, ephemeral.Id,
+	error) {
+
+	//find the channel
+	ch, err := m.getChannel(channelID)
+	if err != nil {
+		return cryptoChannel.MessageID{}, rounds.Round{}, ephemeral.Id{}, err
+	}
+
+	var msgId cryptoChannel.MessageID
+	chMsg := &ChannelMessage{
+		Lease:       validUntil.Nanoseconds(),
+		PayloadType: uint32(messageType),
+		Payload:     msg,
+		Nickname:    AdminUsername,
+		Nonce:       make([]byte, messageNonceSize),
+	}
+
+	// Generate random nonce to be used for message ID generation. This makes it
+	// so two identical messages sent on the same round have different message IDs
+	rng := m.rng.GetStream()
+	n, err := rng.Read(chMsg.Nonce)
+	rng.Close()
+	if err != nil {
+		return cryptoChannel.MessageID{}, rounds.Round{}, ephemeral.Id{},
+			errors.Errorf("Failed to generate nonce: %+v", err)
+	} else if n != messageNonceSize {
+		return cryptoChannel.MessageID{}, rounds.Round{}, ephemeral.Id{},
+			errors.Errorf(
+				"Generated %d bytes for %-byte nonce", n, messageNonceSize)
+	}
+
+	// Note: we are not checking if message is too long before trying to
+	// find a round
+
+	//Build the function pointer that will build the message
+	assemble := func(rid id.Round) ([]byte, error) {
+
+		//Build the message
+		chMsg.RoundID = uint64(rid)
+
+		//Serialize the message
+		chMsgSerial, err := proto.Marshal(chMsg)
+		if err != nil {
+			return nil, err
+		}
+
+		msgId = cryptoChannel.MakeMessageID(chMsgSerial, channelID)
+
+		//check if the message is too long
+		if len(chMsgSerial) > ch.broadcast.MaxRSAToPublicPayloadSize() {
+			return nil, MessageTooLongErr
+		}
+
+		return chMsgSerial, nil
+	}
+
+	uuid, err := m.st.denotePendingAdminSend(channelID, chMsg)
+	if err != nil {
+		return cryptoChannel.MessageID{}, rounds.Round{}, ephemeral.Id{}, err
+	}
+
+	r, ephid, err := ch.broadcast.BroadcastRSAToPublicWithAssembler(privKey,
+		assemble, params)
+	if err != nil {
+		errDenote := m.st.failedSend(uuid)
+		if errDenote != nil {
+			jww.ERROR.Printf("Failed to update for a failed send to "+
+				"%s: %+v", channelID, err)
+		}
+		return cryptoChannel.MessageID{}, rounds.Round{}, ephemeral.Id{}, err
+	}
+
+	err = m.st.send(uuid, msgId, r)
+	if err != nil {
+		return cryptoChannel.MessageID{}, rounds.Round{}, ephemeral.Id{}, err
+	}
+	return msgId, r, ephid, err
+}
+
+// SendMessage is used to send a formatted message over a channel.
+// Due to the underlying encoding using compression, it isn't
+// possible to define the largest payload that can be sent, but
+// it will always be possible to send a payload of 798 bytes at minimum
+func (m *manager) SendMessage(channelID *id.ID, msg string,
+	validUntil time.Duration, params cmix.CMIXParams) (
+	cryptoChannel.MessageID, rounds.Round, ephemeral.Id, error) {
+	txt := &CMIXChannelText{
+		Version:        cmixChannelTextVersion,
+		Text:           msg,
+		ReplyMessageID: nil,
+	}
+
+	txtMarshaled, err := proto.Marshal(txt)
+	if err != nil {
+		return cryptoChannel.MessageID{}, rounds.Round{}, ephemeral.Id{}, err
+	}
+
+	return m.SendGeneric(channelID, Text, txtMarshaled, validUntil, params)
+}
+
+// SendReply is used to send a formatted message over a channel.
+// Due to the underlying encoding using compression, it isn't
+// possible to define the largest payload that can be sent, but
+// it will always be possible to send a payload of 766 bytes at minimum.
+// If the message ID the reply is sent to doesnt exist, the other side will
+// post the message as a normal message and not a reply.
+func (m *manager) SendReply(channelID *id.ID, msg string,
+	replyTo cryptoChannel.MessageID, validUntil time.Duration,
+	params cmix.CMIXParams) (cryptoChannel.MessageID, rounds.Round,
+	ephemeral.Id, error) {
+	txt := &CMIXChannelText{
+		Version:        cmixChannelTextVersion,
+		Text:           msg,
+		ReplyMessageID: replyTo[:],
+	}
+
+	txtMarshaled, err := proto.Marshal(txt)
+	if err != nil {
+		return cryptoChannel.MessageID{}, rounds.Round{}, ephemeral.Id{}, err
+	}
+
+	return m.SendGeneric(channelID, Text, txtMarshaled, validUntil, params)
+}
+
+// SendReaction is used to send a reaction to a message over a channel.
+// The reaction must be a single emoji with no other characters, and will
+// be rejected otherwise.
+// Clients will drop the reaction if they do not recognize the reactTo message
+func (m *manager) SendReaction(channelID *id.ID, reaction string,
+	reactTo cryptoChannel.MessageID, params cmix.CMIXParams) (
+	cryptoChannel.MessageID, rounds.Round, ephemeral.Id, error) {
+
+	if err := ValidateReaction(reaction); err != nil {
+		return cryptoChannel.MessageID{}, rounds.Round{}, ephemeral.Id{}, err
+	}
+
+	react := &CMIXChannelReaction{
+		Version:           cmixChannelReactionVersion,
+		Reaction:          reaction,
+		ReactionMessageID: reactTo[:],
+	}
+
+	reactMarshaled, err := proto.Marshal(react)
+	if err != nil {
+		return cryptoChannel.MessageID{}, rounds.Round{}, ephemeral.Id{}, err
+	}
+
+	return m.SendGeneric(channelID, Reaction, reactMarshaled, ValidForever,
+		params)
+}
diff --git a/channels/sendTracker.go b/channels/sendTracker.go
new file mode 100644
index 0000000000000000000000000000000000000000..023785fa7f4063b6dc30e509419cd79f7978fab4
--- /dev/null
+++ b/channels/sendTracker.go
@@ -0,0 +1,497 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file                                                               //
+////////////////////////////////////////////////////////////////////////////////
+
+package channels
+
+import (
+	"encoding/json"
+	"errors"
+	jww "github.com/spf13/jwalterweatherman"
+	"gitlab.com/elixxir/client/cmix"
+	"gitlab.com/elixxir/client/cmix/identity/receptionID"
+	"gitlab.com/elixxir/client/cmix/rounds"
+	"gitlab.com/elixxir/client/storage/versioned"
+	cryptoChannel "gitlab.com/elixxir/crypto/channel"
+	"gitlab.com/elixxir/crypto/fastRNG"
+	"gitlab.com/elixxir/primitives/states"
+	"gitlab.com/xx_network/primitives/id"
+	"gitlab.com/xx_network/primitives/netTime"
+	"sync"
+	"time"
+)
+
+const (
+	sendTrackerStorageKey     = "sendTrackerStorageKey"
+	sendTrackerStorageVersion = 0
+
+	sendTrackerUnsentStorageKey     = "sendTrackerUnsentStorageKey"
+	sendTrackerUnsentStorageVersion = 0
+
+	getRoundResultsTimeout = 60 * time.Second
+	// number of times it will attempt to get round status before the round
+	// is assumed to have failed. Tracking per round does not persist across
+	// runs
+	maxChecks = 3
+
+	oneSecond = 1000 * time.Millisecond
+)
+
+type tracked struct {
+	MsgID     cryptoChannel.MessageID
+	ChannelID *id.ID
+	RoundID   id.Round
+	UUID      uint64
+}
+
+// the sendTracker tracks outbound messages and denotes when they are delivered
+// to the event model. It also captures incoming messages and in the event they
+// were sent by this user diverts them as status updates on the previously sent
+// messages
+type sendTracker struct {
+	byRound map[id.Round][]*tracked
+
+	byMessageID map[cryptoChannel.MessageID]*tracked
+
+	unsent map[uint64]*tracked
+
+	mux sync.RWMutex
+
+	trigger      triggerEventFunc
+	adminTrigger triggerAdminEventFunc
+	updateStatus updateStatusFunc
+
+	net Client
+
+	kv *versioned.KV
+
+	rngSrc *fastRNG.StreamGenerator
+}
+
+// messageReceiveFunc is a function type for sendTracker.MessageReceive so it
+// can be mocked for testing where used
+type messageReceiveFunc func(messageID cryptoChannel.MessageID, r rounds.Round) bool
+
+// loadSendTracker loads a sent tracker, restoring from disk. It will register a
+// function with the cmix client, delayed on when the network goes healthy,
+// which will attempt to discover the status of all rounds that are outstanding.
+func loadSendTracker(net Client, kv *versioned.KV, trigger triggerEventFunc,
+	adminTrigger triggerAdminEventFunc, updateStatus updateStatusFunc,
+	rngSource *fastRNG.StreamGenerator) *sendTracker {
+	st := &sendTracker{
+		byRound:      make(map[id.Round][]*tracked),
+		byMessageID:  make(map[cryptoChannel.MessageID]*tracked),
+		unsent:       make(map[uint64]*tracked),
+		trigger:      trigger,
+		adminTrigger: adminTrigger,
+		updateStatus: updateStatus,
+		net:          net,
+		kv:           kv,
+		rngSrc:       rngSource,
+	}
+
+	/*if err := st.load(); !kv.Exists(err){
+		jww.FATAL.Panicf("failed to load sent tracker: %+v", err)
+	}*/
+	st.load()
+
+	//denote all unsent messages as failed and clear
+	for uuid, t := range st.unsent {
+		updateStatus(uuid, t.MsgID,
+			time.Time{}, rounds.Round{}, Failed)
+	}
+	st.unsent = make(map[uint64]*tracked)
+
+	//register to check all outstanding rounds when the network becomes healthy
+	/*var callBackID uint64
+	callBackID = net.AddHealthCallback(func(f bool) {
+		if !f {
+			return
+		}
+		net.RemoveHealthCallback(callBackID)
+		for rid := range st.byRound {
+
+			rr := &roundResults{
+				round: rid,
+				st:    st,
+			}
+			st.net.GetRoundResults(getRoundResultsTimeout, rr.callback, rr.round)
+		}
+	})*/
+
+	return st
+}
+
+// store writes the list of rounds that have been
+func (st *sendTracker) store() error {
+
+	if err := st.storeSent(); err != nil {
+		return err
+	}
+
+	return st.storeUnsent()
+}
+
+func (st *sendTracker) storeSent() error {
+
+	//save sent messages
+	data, err := json.Marshal(&st.byRound)
+	if err != nil {
+		return err
+	}
+	return st.kv.Set(sendTrackerStorageKey, &versioned.Object{
+		Version:   sendTrackerStorageVersion,
+		Timestamp: netTime.Now(),
+		Data:      data,
+	})
+}
+
+// store writes the list of rounds that have been
+func (st *sendTracker) storeUnsent() error {
+	//save unsent messages
+	data, err := json.Marshal(&st.unsent)
+	if err != nil {
+		return err
+	}
+
+	return st.kv.Set(sendTrackerUnsentStorageKey, &versioned.Object{
+		Version:   sendTrackerUnsentStorageVersion,
+		Timestamp: netTime.Now(),
+		Data:      data,
+	})
+}
+
+// load will get the stored rounds to be checked from disk and builds
+// internal datastructures
+func (st *sendTracker) load() error {
+	obj, err := st.kv.Get(sendTrackerStorageKey, sendTrackerStorageVersion)
+	if err != nil {
+		return err
+	}
+
+	err = json.Unmarshal(obj.Data, &st.byRound)
+	if err != nil {
+		return err
+	}
+
+	for rid := range st.byRound {
+		roundList := st.byRound[rid]
+		for j := range roundList {
+			st.byMessageID[roundList[j].MsgID] = roundList[j]
+		}
+	}
+
+	obj, err = st.kv.Get(sendTrackerUnsentStorageKey, sendTrackerUnsentStorageVersion)
+	if err != nil {
+		return err
+	}
+
+	err = json.Unmarshal(obj.Data, &st.unsent)
+	if err != nil {
+		return err
+	}
+
+	return nil
+}
+
+// denotePendingSend is called before the pending send. It tracks the send
+// internally and notifies the UI of the send
+func (st *sendTracker) denotePendingSend(channelID *id.ID,
+	umi *userMessageInternal) (uint64, error) {
+	// for a timestamp for the message, use 1 second from now to
+	// approximate the lag due to round submission
+	ts := netTime.Now().Add(oneSecond)
+
+	// create a random message id so there will not be collisions in a database
+	// that requires a unique message ID
+	stream := st.rngSrc.GetStream()
+	umi.messageID = cryptoChannel.MessageID{}
+	num, err := stream.Read(umi.messageID[:])
+	if num != len(umi.messageID[:]) || err != nil {
+		jww.FATAL.Panicf("failed to get a random message ID, read "+
+			"len: %d, err: %+v", num, err)
+	}
+	stream.Close()
+
+	// submit the message to the UI
+	uuid, err := st.trigger(channelID, umi, ts, receptionID.EphemeralIdentity{},
+		rounds.Round{}, Unsent)
+	if err != nil {
+		return 0, err
+	}
+
+	// track the message on disk
+	st.handleDenoteSend(uuid, channelID, umi.messageID,
+		rounds.Round{})
+	return uuid, nil
+}
+
+// denotePendingAdminSend is called before the pending admin send. It tracks the
+// send internally and notifies the UI of the send
+func (st *sendTracker) denotePendingAdminSend(channelID *id.ID,
+	cm *ChannelMessage) (uint64, error) {
+	// for a timestamp for the message, use 1 second from now to
+	// approximate the lag due to round submission
+	ts := netTime.Now().Add(oneSecond)
+
+	// create a random message id so there will not be collisions in a database
+	// that requires a unique message ID
+	stream := st.rngSrc.GetStream()
+	randMid := cryptoChannel.MessageID{}
+	num, err := stream.Read(randMid[:])
+	if num != len(randMid[:]) || err != nil {
+		jww.FATAL.Panicf("failed to get a random message ID, read "+
+			"len: %d, err: %+v", num, err)
+	}
+	stream.Close()
+
+	// submit the message to the UI
+	uuid, err := st.adminTrigger(channelID, cm, ts, randMid,
+		receptionID.EphemeralIdentity{},
+		rounds.Round{}, Unsent)
+
+	if err != nil {
+		return 0, err
+	}
+
+	// track the message on disk
+	st.handleDenoteSend(uuid, channelID, randMid,
+		rounds.Round{})
+	return uuid, nil
+}
+
+// handleDenoteSend does the nity gritty of editing internal structures
+func (st *sendTracker) handleDenoteSend(uuid uint64, channelID *id.ID,
+	messageID cryptoChannel.MessageID, round rounds.Round) {
+	st.mux.Lock()
+	defer st.mux.Unlock()
+
+	//skip if already added
+	_, existsMessage := st.unsent[uuid]
+	if existsMessage {
+		return
+	}
+
+	st.unsent[uuid] = &tracked{messageID, channelID, round.ID, uuid}
+
+	err := st.storeUnsent()
+	if err != nil {
+		jww.FATAL.Panicf(err.Error())
+	}
+}
+
+// send tracks a generic send message
+func (st *sendTracker) send(uuid uint64, msgID cryptoChannel.MessageID,
+	round rounds.Round) error {
+
+	// update the on disk message status
+	t, err := st.handleSend(uuid, msgID, round)
+	if err != nil {
+		return err
+	}
+
+	// Modify the timestamp to reduce the chance message order will be ambiguous
+	ts := mutateTimestamp(round.Timestamps[states.QUEUED], msgID)
+
+	//update the message on the UI
+	go st.updateStatus(t.UUID, msgID, ts, round, Sent)
+	return nil
+}
+
+// send tracks a generic send message
+func (st *sendTracker) failedSend(uuid uint64) error {
+
+	// update the on disk message status
+	t, err := st.handleSendFailed(uuid)
+	if err != nil {
+		return err
+	}
+
+	//update the message on the UI
+	go st.updateStatus(t.UUID, cryptoChannel.MessageID{}, time.Time{}, rounds.Round{}, Failed)
+	return nil
+}
+
+// handleSend does the nity gritty of editing internal structures
+func (st *sendTracker) handleSend(uuid uint64,
+	messageID cryptoChannel.MessageID, round rounds.Round) (*tracked, error) {
+	st.mux.Lock()
+	defer st.mux.Unlock()
+
+	//check if in unsent
+	t, exists := st.unsent[uuid]
+	if !exists {
+		return nil, errors.New("cannot handle send on an unprepared message")
+	}
+
+	_, existsMessage := st.byMessageID[messageID]
+	if existsMessage {
+		return nil, errors.New("cannot handle send on a message which was " +
+			"already sent")
+	}
+
+	t.MsgID = messageID
+	t.RoundID = round.ID
+
+	//add the roundID
+	roundsList, _ := st.byRound[round.ID]
+	st.byRound[round.ID] = append(roundsList, t)
+
+	//add the round
+	st.byMessageID[messageID] = t
+
+	/*if !existsRound {
+		rr := &roundResults{
+			round: round.ID,
+			st:    st,
+		}
+		st.net.GetRoundResults(getRoundResultsTimeout, rr.callback, rr.round)
+	}*/
+
+	delete(st.unsent, uuid)
+
+	//store the changed list to disk
+	err := st.store()
+	if err != nil {
+		jww.FATAL.Panicf(err.Error())
+	}
+
+	return t, nil
+}
+
+// handleSendFailed does the nity gritty of editing internal structures
+func (st *sendTracker) handleSendFailed(uuid uint64) (*tracked, error) {
+	st.mux.Lock()
+	defer st.mux.Unlock()
+
+	//check if in unsent
+	t, exists := st.unsent[uuid]
+	if !exists {
+		return nil, errors.New("cannot handle send on an unprepared message")
+	}
+
+	delete(st.unsent, uuid)
+
+	//store the changed list to disk
+	err := st.storeUnsent()
+	if err != nil {
+		jww.FATAL.Panicf(err.Error())
+	}
+
+	return t, nil
+}
+
+// MessageReceive is used when a message is received to check if the message
+// was sent by this user. If it was, the correct signal is sent to the event
+// model and the function returns true, notifying the caller to not process
+// the message
+func (st *sendTracker) MessageReceive(messageID cryptoChannel.MessageID, round rounds.Round) bool {
+	st.mux.RLock()
+
+	//skip if already added
+	_, existsMessage := st.byMessageID[messageID]
+	st.mux.RUnlock()
+	if !existsMessage {
+		return false
+	}
+
+	st.mux.Lock()
+	defer st.mux.Unlock()
+	msgData, existsMessage := st.byMessageID[messageID]
+	if !existsMessage {
+		return false
+	}
+
+	delete(st.byMessageID, messageID)
+
+	roundList := st.byRound[msgData.RoundID]
+	if len(roundList) == 1 {
+		delete(st.byRound, msgData.RoundID)
+	} else {
+		newRoundList := make([]*tracked, 0, len(roundList)-1)
+		for i := range roundList {
+			if !roundList[i].MsgID.Equals(messageID) {
+				newRoundList = append(newRoundList, roundList[i])
+			}
+		}
+		st.byRound[msgData.RoundID] = newRoundList
+	}
+
+	ts := mutateTimestamp(round.Timestamps[states.QUEUED], messageID)
+	go st.updateStatus(msgData.UUID, messageID, ts,
+		round, Delivered)
+
+	if err := st.storeSent(); err != nil {
+		jww.FATAL.Panicf("failed to store the updated sent list: %+v", err)
+	}
+
+	return true
+}
+
+// roundResults represents a round which results are waiting on from the cmix layer
+type roundResults struct {
+	round     id.Round
+	st        *sendTracker
+	numChecks uint
+}
+
+// callback is called when results are known about a round. it will re-trigger
+// the wait if it fails up to 'maxChecks' times.
+func (rr *roundResults) callback(allRoundsSucceeded, timedOut bool, results map[id.Round]cmix.RoundResult) {
+
+	rr.st.mux.Lock()
+
+	//if the message was already handled, do nothing
+	registered, existsRound := rr.st.byRound[rr.round]
+	if !existsRound {
+		rr.st.mux.Unlock()
+		return
+	}
+
+	status := Delivered
+	if !allRoundsSucceeded {
+		status = Failed
+	}
+
+	if timedOut {
+		if rr.numChecks >= maxChecks {
+			jww.WARN.Printf("Channel messages sent on %d assumed to "+
+				"have failed after %d attempts to get round status", rr.round,
+				maxChecks)
+			status = Failed
+		} else {
+			rr.numChecks++
+
+			rr.st.mux.Unlock()
+
+			//retry if timed out
+			go rr.st.net.GetRoundResults(getRoundResultsTimeout, rr.callback, []id.Round{rr.round}...)
+			return
+		}
+
+	}
+
+	delete(rr.st.byRound, rr.round)
+
+	for i := range registered {
+		delete(rr.st.byMessageID, registered[i].MsgID)
+	}
+
+	if err := rr.st.store(); err != nil {
+		jww.FATAL.Panicf("failed to store update after "+
+			"finalizing delivery of sent messages: %+v", err)
+	}
+
+	rr.st.mux.Unlock()
+
+	for i := range registered {
+		round := results[rr.round].Round
+		ts := mutateTimestamp(round.Timestamps[states.QUEUED], registered[i].MsgID)
+		go rr.st.updateStatus(registered[i].UUID, registered[i].MsgID, ts,
+			round, status)
+	}
+
+}
diff --git a/channels/sendTracker_test.go b/channels/sendTracker_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..c2062c6d8c514983b2ab8950fb7b7dc41567a0f6
--- /dev/null
+++ b/channels/sendTracker_test.go
@@ -0,0 +1,351 @@
+package channels
+
+import (
+	"gitlab.com/elixxir/client/cmix"
+	"gitlab.com/elixxir/client/cmix/identity/receptionID"
+	"gitlab.com/elixxir/client/cmix/message"
+	"gitlab.com/elixxir/client/cmix/rounds"
+	"gitlab.com/elixxir/client/storage/versioned"
+	cryptoChannel "gitlab.com/elixxir/crypto/channel"
+	"gitlab.com/elixxir/crypto/fastRNG"
+	"gitlab.com/elixxir/ekv"
+	"gitlab.com/elixxir/primitives/states"
+	"gitlab.com/xx_network/crypto/csprng"
+	"gitlab.com/xx_network/primitives/id"
+	"gitlab.com/xx_network/primitives/id/ephemeral"
+	"gitlab.com/xx_network/primitives/netTime"
+	"testing"
+	"time"
+)
+
+type mockClient struct{}
+
+func (mc *mockClient) GetMaxMessageLength() int {
+	return 2048
+}
+func (mc *mockClient) SendWithAssembler(recipient *id.ID, assembler cmix.MessageAssembler,
+	cmixParams cmix.CMIXParams) (rounds.Round, ephemeral.Id, error) {
+	return rounds.Round{}, ephemeral.Id{}, nil
+}
+func (mc *mockClient) IsHealthy() bool {
+	return true
+}
+func (mc *mockClient) AddIdentity(id *id.ID, validUntil time.Time, persistent bool) {}
+func (mc *mockClient) AddService(clientID *id.ID, newService message.Service,
+	response message.Processor) {
+}
+func (mc *mockClient) DeleteClientService(clientID *id.ID) {}
+func (mc *mockClient) RemoveIdentity(id *id.ID)            {}
+func (mc *mockClient) GetRoundResults(timeout time.Duration, roundCallback cmix.RoundEventCallback,
+	roundList ...id.Round) {
+}
+func (mc *mockClient) AddHealthCallback(f func(bool)) uint64 {
+	return 0
+}
+func (mc *mockClient) RemoveHealthCallback(uint64) {}
+
+// Test MessageReceive basic logic
+func TestSendTracker_MessageReceive(t *testing.T) {
+	kv := versioned.NewKV(ekv.MakeMemstore())
+	uuidNum := uint64(0)
+	rid := id.Round(2)
+
+	r := rounds.Round{
+		ID:         rid,
+		Timestamps: make(map[states.Round]time.Time),
+	}
+	r.Timestamps[states.QUEUED] = time.Now()
+	trigger := func(chID *id.ID, umi *userMessageInternal, ts time.Time,
+		receptionID receptionID.EphemeralIdentity, round rounds.Round,
+		status SentStatus) (uint64, error) {
+		oldUUID := uuidNum
+		uuidNum++
+		return oldUUID, nil
+	}
+
+	updateStatus := func(uuid uint64, messageID cryptoChannel.MessageID,
+		timestamp time.Time, round rounds.Round, status SentStatus) {
+	}
+
+	cid := id.NewIdFromString("channel", id.User, t)
+
+	crng := fastRNG.NewStreamGenerator(100, 5, csprng.NewSystemRNG)
+
+	st := loadSendTracker(&mockClient{}, kv, trigger, nil, updateStatus, crng)
+
+	mid := cryptoChannel.MakeMessageID([]byte("hello"), cid)
+	process := st.MessageReceive(mid, r)
+	if process {
+		t.Fatalf("Did not receive expected result from MessageReceive")
+	}
+
+	uuid, err := st.denotePendingSend(cid, &userMessageInternal{
+		userMessage: &UserMessage{},
+		channelMessage: &ChannelMessage{
+			Lease:       netTime.Now().UnixNano(),
+			RoundID:     uint64(rid),
+			PayloadType: 0,
+			Payload:     []byte("hello"),
+		}})
+	if err != nil {
+		t.Fatalf(err.Error())
+	}
+
+	err = st.send(uuid, mid, rounds.Round{
+		ID:    rid,
+		State: 1,
+	})
+	if err != nil {
+		t.Fatalf(err.Error())
+	}
+	process = st.MessageReceive(mid, r)
+	if !process {
+		t.Fatalf("Did not receive expected result from MessageReceive")
+	}
+
+	cid2 := id.NewIdFromString("channel two", id.User, t)
+	uuid2, err := st.denotePendingSend(cid2, &userMessageInternal{
+		userMessage: &UserMessage{},
+		channelMessage: &ChannelMessage{
+			Lease:       netTime.Now().UnixNano(),
+			RoundID:     uint64(rid),
+			PayloadType: 0,
+			Payload:     []byte("hello again"),
+		}})
+	if err != nil {
+		t.Fatalf(err.Error())
+	}
+
+	err = st.send(uuid2, mid, rounds.Round{
+		ID:    rid,
+		State: 1,
+	})
+	process = st.MessageReceive(mid, r)
+	if !process {
+		t.Fatalf("Did not receive expected result from MessageReceive")
+	}
+}
+
+// Test failedSend function, confirming that data is stored appropriately
+// and callbacks are called
+func TestSendTracker_failedSend(t *testing.T) {
+	triggerCh := make(chan SentStatus)
+
+	kv := versioned.NewKV(ekv.MakeMemstore())
+
+	adminTrigger := func(chID *id.ID, cm *ChannelMessage, ts time.Time,
+		messageID cryptoChannel.MessageID, receptionID receptionID.EphemeralIdentity,
+		round rounds.Round, status SentStatus) (uint64, error) {
+		return 0, nil
+	}
+
+	updateStatus := func(uuid uint64, messageID cryptoChannel.MessageID,
+		timestamp time.Time, round rounds.Round, status SentStatus) {
+		triggerCh <- status
+	}
+
+	crng := fastRNG.NewStreamGenerator(100, 5, csprng.NewSystemRNG)
+
+	st := loadSendTracker(&mockClient{}, kv, nil, adminTrigger, updateStatus, crng)
+
+	cid := id.NewIdFromString("channel", id.User, t)
+	mid := cryptoChannel.MakeMessageID([]byte("hello"), cid)
+	rid := id.Round(2)
+	uuid, err := st.denotePendingAdminSend(cid, &ChannelMessage{
+		Lease:       0,
+		RoundID:     uint64(rid),
+		PayloadType: 0,
+		Payload:     []byte("hello"),
+	})
+	if err != nil {
+		t.Fatalf(err.Error())
+	}
+
+	err = st.failedSend(uuid)
+	if err != nil {
+		t.Fatalf(err.Error())
+	}
+
+	timeout := time.NewTicker(time.Second * 5)
+	select {
+	case s := <-triggerCh:
+		if s != Failed {
+			t.Fatalf("Did not receive failed from failed message")
+		}
+		t.Log("Received over trigger chan")
+	case <-timeout.C:
+		t.Fatal("Timed out waiting for trigger chan")
+	}
+
+	trackedRound, ok := st.byRound[rid]
+	if ok {
+		t.Fatal("Should not have found a tracked round")
+	}
+	if len(trackedRound) != 0 {
+		t.Fatal("Did not find expected number of trackedRounds")
+	}
+
+	_, ok = st.byMessageID[mid]
+	if ok {
+		t.Error("Should not have found tracked message")
+	}
+
+	_, ok = st.unsent[uuid]
+	if ok {
+		t.Fatal("Should not have found an unsent")
+	}
+}
+
+// Test send tracker send function, confirming that data is stored appropriately
+//// and callbacks are called
+func TestSendTracker_send(t *testing.T) {
+	triggerCh := make(chan bool)
+
+	kv := versioned.NewKV(ekv.MakeMemstore())
+	trigger := func(chID *id.ID, umi *userMessageInternal, ts time.Time,
+		receptionID receptionID.EphemeralIdentity, round rounds.Round, status SentStatus) (uint64, error) {
+		return 0, nil
+	}
+
+	updateStatus := func(uuid uint64, messageID cryptoChannel.MessageID,
+		timestamp time.Time, round rounds.Round, status SentStatus) {
+		triggerCh <- true
+	}
+
+	crng := fastRNG.NewStreamGenerator(100, 5, csprng.NewSystemRNG)
+
+	st := loadSendTracker(&mockClient{}, kv, trigger, nil, updateStatus, crng)
+
+	cid := id.NewIdFromString("channel", id.User, t)
+	mid := cryptoChannel.MakeMessageID([]byte("hello"), cid)
+	rid := id.Round(2)
+	uuid, err := st.denotePendingSend(cid, &userMessageInternal{
+		userMessage: &UserMessage{},
+		channelMessage: &ChannelMessage{
+			Lease:       0,
+			RoundID:     uint64(rid),
+			PayloadType: 0,
+			Payload:     []byte("hello"),
+		},
+		messageID: mid,
+	})
+	if err != nil {
+		t.Fatalf(err.Error())
+	}
+
+	err = st.send(uuid, mid, rounds.Round{
+		ID:    rid,
+		State: 2,
+	})
+	if err != nil {
+		t.Fatalf(err.Error())
+	}
+
+	timeout := time.NewTicker(time.Second * 5)
+	select {
+	case <-triggerCh:
+		t.Log("Received over trigger chan")
+	case <-timeout.C:
+		t.Fatal("Timed out waiting for trigger chan")
+	}
+
+	trackedRound, ok := st.byRound[rid]
+	if !ok {
+		t.Fatal("Should have found a tracked round")
+	}
+	if len(trackedRound) != 1 {
+		t.Fatal("Did not find expected number of trackedRounds")
+	}
+	if trackedRound[0].MsgID != mid {
+		t.Fatalf("Did not find expected message ID in trackedRounds")
+	}
+
+	trackedMsg, ok := st.byMessageID[mid]
+	if !ok {
+		t.Error("Should have found tracked message")
+	}
+	if trackedMsg.MsgID != mid {
+		t.Fatalf("Did not find expected message ID in byMessageID")
+	}
+}
+
+// Test loading stored byRound map from storage
+func TestSendTracker_load_store(t *testing.T) {
+	kv := versioned.NewKV(ekv.MakeMemstore())
+
+	crng := fastRNG.NewStreamGenerator(100, 5, csprng.NewSystemRNG)
+
+	st := loadSendTracker(&mockClient{}, kv, nil, nil, nil, crng)
+	cid := id.NewIdFromString("channel", id.User, t)
+	mid := cryptoChannel.MakeMessageID([]byte("hello"), cid)
+	rid := id.Round(2)
+	st.byRound[rid] = []*tracked{{MsgID: mid, ChannelID: cid, RoundID: rid}}
+	err := st.store()
+	if err != nil {
+		t.Fatalf("Failed to store byRound: %+v", err)
+	}
+
+	st2 := loadSendTracker(&mockClient{}, kv, nil, nil, nil, crng)
+	if len(st2.byRound) != len(st.byRound) {
+		t.Fatalf("byRound was not properly loaded")
+	}
+}
+
+func TestRoundResult_callback(t *testing.T) {
+	kv := versioned.NewKV(ekv.MakeMemstore())
+	triggerCh := make(chan bool)
+	update := func(uuid uint64, messageID cryptoChannel.MessageID,
+		timestamp time.Time, round rounds.Round, status SentStatus) {
+		triggerCh <- true
+	}
+	trigger := func(chID *id.ID, umi *userMessageInternal, ts time.Time,
+		receptionID receptionID.EphemeralIdentity, round rounds.Round,
+		status SentStatus) (uint64, error) {
+		return 0, nil
+	}
+
+	crng := fastRNG.NewStreamGenerator(100, 5, csprng.NewSystemRNG)
+
+	st := loadSendTracker(&mockClient{}, kv, trigger, nil, update, crng)
+
+	cid := id.NewIdFromString("channel", id.User, t)
+	mid := cryptoChannel.MakeMessageID([]byte("hello"), cid)
+	rid := id.Round(2)
+	uuid, err := st.denotePendingSend(cid, &userMessageInternal{
+		userMessage: &UserMessage{},
+		channelMessage: &ChannelMessage{
+			Lease:       0,
+			RoundID:     uint64(rid),
+			PayloadType: 0,
+			Payload:     []byte("hello"),
+		},
+		messageID: mid,
+	})
+	if err != nil {
+		t.Fatalf(err.Error())
+	}
+
+	err = st.send(uuid, mid, rounds.Round{
+		ID:    rid,
+		State: 2,
+	})
+
+	rr := roundResults{
+		round:     rid,
+		st:        st,
+		numChecks: 0,
+	}
+
+	rr.callback(true, false, map[id.Round]cmix.RoundResult{rid: {cmix.Succeeded, rounds.Round{
+		ID:    rid,
+		State: 0,
+	}}})
+
+	timeout := time.NewTicker(time.Second * 5)
+	select {
+	case <-triggerCh:
+		t.Log("Received trigger")
+	case <-timeout.C:
+		t.Fatal("Did not receive update")
+	}
+}
diff --git a/channels/send_test.go b/channels/send_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..c3c8114c85d69193216c04bf903991f69129917e
--- /dev/null
+++ b/channels/send_test.go
@@ -0,0 +1,616 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file                                                               //
+////////////////////////////////////////////////////////////////////////////////
+
+package channels
+
+import (
+	"bytes"
+	"crypto/ed25519"
+	"github.com/golang/protobuf/proto"
+	"gitlab.com/elixxir/client/cmix/identity/receptionID"
+	"gitlab.com/elixxir/client/cmix/rounds"
+	"gitlab.com/elixxir/client/storage/versioned"
+	cryptoChannel "gitlab.com/elixxir/crypto/channel"
+	"gitlab.com/elixxir/crypto/fastRNG"
+	"gitlab.com/elixxir/crypto/rsa"
+	"gitlab.com/elixxir/ekv"
+	"gitlab.com/xx_network/crypto/csprng"
+	"gitlab.com/xx_network/primitives/netTime"
+	"math/rand"
+	"sync"
+	"testing"
+	"time"
+
+	"gitlab.com/xx_network/primitives/id"
+	"gitlab.com/xx_network/primitives/id/ephemeral"
+
+	"gitlab.com/elixxir/client/broadcast"
+	"gitlab.com/elixxir/client/cmix"
+	cryptoBroadcast "gitlab.com/elixxir/crypto/broadcast"
+)
+
+const returnedRound = 42
+
+type mockBroadcastChannel struct {
+	hasRun bool
+
+	payload []byte
+	params  cmix.CMIXParams
+
+	pk rsa.PrivateKey
+
+	crypto *cryptoBroadcast.Channel
+}
+
+func (m *mockBroadcastChannel) MaxPayloadSize() int {
+	return 1024
+}
+
+func (m *mockBroadcastChannel) MaxRSAToPublicPayloadSize() int {
+	return 512
+}
+
+func (m *mockBroadcastChannel) Get() *cryptoBroadcast.Channel {
+	return m.crypto
+}
+
+func (m *mockBroadcastChannel) Broadcast(payload []byte, cMixParams cmix.CMIXParams) (
+	rounds.Round, ephemeral.Id, error) {
+
+	m.hasRun = true
+
+	m.payload = payload
+	m.params = cMixParams
+
+	return rounds.Round{ID: 123}, ephemeral.Id{}, nil
+}
+
+func (m *mockBroadcastChannel) BroadcastWithAssembler(assembler broadcast.Assembler, cMixParams cmix.CMIXParams) (
+	rounds.Round, ephemeral.Id, error) {
+	m.hasRun = true
+
+	var err error
+
+	m.payload, err = assembler(returnedRound)
+	m.params = cMixParams
+
+	return rounds.Round{ID: 123}, ephemeral.Id{}, err
+}
+
+func (m *mockBroadcastChannel) BroadcastRSAtoPublic(pk rsa.PrivateKey, payload []byte,
+	cMixParams cmix.CMIXParams) (rounds.Round, ephemeral.Id, error) {
+	m.hasRun = true
+
+	m.payload = payload
+	m.params = cMixParams
+
+	m.pk = pk
+	return rounds.Round{ID: 123}, ephemeral.Id{}, nil
+}
+
+func (m *mockBroadcastChannel) BroadcastRSAToPublicWithAssembler(
+	pk rsa.PrivateKey, assembler broadcast.Assembler,
+	cMixParams cmix.CMIXParams) (rounds.Round, ephemeral.Id, error) {
+
+	m.hasRun = true
+
+	var err error
+
+	m.payload, err = assembler(returnedRound)
+	m.params = cMixParams
+
+	m.pk = pk
+
+	return rounds.Round{ID: 123}, ephemeral.Id{}, err
+}
+
+func (m *mockBroadcastChannel) RegisterListener(listenerCb broadcast.ListenerFunc, method broadcast.Method) error {
+	return nil
+}
+
+func (m *mockBroadcastChannel) Stop() {
+}
+
+type mockNameService struct {
+	validChMsg bool
+}
+
+func (m *mockNameService) GetUsername() string {
+	return "Alice"
+}
+
+func (m *mockNameService) GetChannelValidationSignature() (signature []byte, lease time.Time) {
+	return []byte("fake validation sig"), netTime.Now()
+}
+
+func (m *mockNameService) GetChannelPubkey() ed25519.PublicKey {
+	return []byte("fake pubkey")
+}
+
+func (m *mockNameService) SignChannelMessage(message []byte) (signature []byte, err error) {
+	return []byte("fake sig"), nil
+}
+
+func (m *mockNameService) ValidateChannelMessage(username string, lease time.Time,
+	pubKey ed25519.PublicKey, authorIDSignature []byte) bool {
+	return m.validChMsg
+}
+
+func TestSendGeneric(t *testing.T) {
+
+	nameService := new(mockNameService)
+	nameService.validChMsg = true
+
+	rng := rand.New(rand.NewSource(64))
+
+	pi, err := cryptoChannel.GenerateIdentity(rng)
+	if err != nil {
+		t.Fatalf(err.Error())
+	}
+
+	crng := fastRNG.NewStreamGenerator(100, 5, csprng.NewSystemRNG)
+
+	m := &manager{
+		me:       pi,
+		channels: make(map[id.ID]*joinedChannel),
+		mux:      sync.RWMutex{},
+		rng:      fastRNG.NewStreamGenerator(1000, 10, csprng.NewSystemRNG),
+		nicknameManager: &nicknameManager{
+			byChannel: make(map[id.ID]string),
+			kv:        nil,
+		},
+		st: loadSendTracker(&mockBroadcastClient{},
+			versioned.NewKV(ekv.MakeMemstore()), func(chID *id.ID,
+				umi *userMessageInternal, ts time.Time,
+				receptionID receptionID.EphemeralIdentity,
+				round rounds.Round, status SentStatus) (uint64, error) {
+				return 0, nil
+			}, func(chID *id.ID, cm *ChannelMessage, ts time.Time,
+				messageID cryptoChannel.MessageID, receptionID receptionID.EphemeralIdentity,
+				round rounds.Round, status SentStatus) (uint64, error) {
+				return 0, nil
+			}, func(uuid uint64, messageID cryptoChannel.MessageID,
+				timestamp time.Time, round rounds.Round, status SentStatus) {
+			}, crng),
+	}
+
+	channelID := new(id.ID)
+	messageType := Text
+	msg := []byte("hello world")
+	validUntil := time.Hour
+	params := new(cmix.CMIXParams)
+
+	mbc := &mockBroadcastChannel{}
+
+	m.channels[*channelID] = &joinedChannel{
+		broadcast: mbc,
+	}
+
+	messageId, roundId, ephemeralId, err := m.SendGeneric(
+		channelID,
+		messageType,
+		msg,
+		validUntil,
+		*params)
+	if err != nil {
+		t.Logf("ERROR %v", err)
+		t.Fail()
+	}
+	t.Logf("messageId %v, roundId %v, ephemeralId %v", messageId, roundId, ephemeralId)
+
+	// verify the message was handled correctly
+
+	// decode the user message
+	umi, err := unmarshalUserMessageInternal(mbc.payload, channelID)
+	if err != nil {
+		t.Fatalf("Failed to decode the user message: %s", err)
+	}
+
+	// do checks of the data
+	if !umi.GetMessageID().Equals(messageId) {
+		t.Errorf("The message IDs do not match. %s vs %s ",
+			umi.messageID, messageId)
+	}
+
+	if !bytes.Equal(umi.GetChannelMessage().Payload, msg) {
+		t.Errorf("The payload does not match. %s vs %s ",
+			umi.GetChannelMessage().Payload, msg)
+	}
+
+	if MessageType(umi.GetChannelMessage().PayloadType) != messageType {
+		t.Fatalf("Message types do not match, %s vs %s",
+			MessageType(umi.GetChannelMessage().PayloadType), messageType)
+	}
+
+	if umi.GetChannelMessage().RoundID != returnedRound {
+		t.Errorf("The returned round is incorrect, %d vs %d",
+			umi.GetChannelMessage().RoundID, returnedRound)
+	}
+
+}
+
+func TestAdminGeneric(t *testing.T) {
+
+	prng := rand.New(rand.NewSource(64))
+
+	pi, err := cryptoChannel.GenerateIdentity(prng)
+	if err != nil {
+		t.Fatalf(err.Error())
+	}
+
+	crng := fastRNG.NewStreamGenerator(100, 5, csprng.NewSystemRNG)
+
+	m := &manager{
+		channels: make(map[id.ID]*joinedChannel),
+		nicknameManager: &nicknameManager{
+			byChannel: make(map[id.ID]string),
+			kv:        nil,
+		},
+		me:  pi,
+		rng: fastRNG.NewStreamGenerator(1000, 10, csprng.NewSystemRNG),
+		st: loadSendTracker(&mockBroadcastClient{},
+			versioned.NewKV(ekv.MakeMemstore()), func(chID *id.ID,
+				umi *userMessageInternal, ts time.Time,
+				receptionID receptionID.EphemeralIdentity,
+				round rounds.Round, status SentStatus) (uint64, error) {
+				return 0, nil
+			}, func(chID *id.ID, cm *ChannelMessage, ts time.Time,
+				messageID cryptoChannel.MessageID, receptionID receptionID.EphemeralIdentity,
+				round rounds.Round, status SentStatus) (uint64, error) {
+				return 0, nil
+			}, func(uuid uint64, messageID cryptoChannel.MessageID,
+				timestamp time.Time, round rounds.Round, status SentStatus) {
+			}, crng),
+	}
+
+	messageType := Text
+	msg := []byte("hello world")
+	validUntil := time.Hour
+
+	rng := &csprng.SystemRNG{}
+	ch, priv, err := cryptoBroadcast.NewChannel("test", "test",
+		1000, rng)
+	if err != nil {
+		t.Fatalf("Failed to generate channel: %+v", err)
+	}
+
+	mbc := &mockBroadcastChannel{crypto: ch}
+
+	m.channels[*ch.ReceptionID] = &joinedChannel{
+		broadcast: mbc,
+	}
+
+	messageId, roundId, ephemeralId, err := m.SendAdminGeneric(priv,
+		ch.ReceptionID, messageType, msg, validUntil, cmix.GetDefaultCMIXParams())
+	if err != nil {
+		t.Fatalf("Failed to SendAdminGeneric: %v", err)
+	}
+	t.Logf("messageId %v, roundId %v, ephemeralId %v", messageId, roundId, ephemeralId)
+
+	// verify the message was handled correctly
+
+	msgID := cryptoChannel.MakeMessageID(mbc.payload, ch.ReceptionID)
+
+	if !msgID.Equals(messageId) {
+		t.Errorf("The message IDs do not match. %s vs %s ",
+			msgID, messageId)
+	}
+
+	// decode the channel message
+	chMgs := &ChannelMessage{}
+	err = proto.Unmarshal(mbc.payload, chMgs)
+	if err != nil {
+		t.Fatalf("Failed to decode the channel message: %s", err)
+	}
+
+	if !bytes.Equal(chMgs.Payload, msg) {
+		t.Errorf("Messages do not match, %s vs %s", chMgs.Payload, msg)
+	}
+
+	if MessageType(chMgs.PayloadType) != messageType {
+		t.Errorf("Message types do not match, %s vs %s",
+			MessageType(chMgs.PayloadType), messageType)
+	}
+
+	if chMgs.RoundID != returnedRound {
+		t.Errorf("The returned round is incorrect, %d vs %d",
+			chMgs.RoundID, returnedRound)
+	}
+}
+
+func TestSendMessage(t *testing.T) {
+
+	nameService := new(mockNameService)
+	nameService.validChMsg = true
+
+	prng := rand.New(rand.NewSource(64))
+
+	pi, err := cryptoChannel.GenerateIdentity(prng)
+	if err != nil {
+		t.Fatalf(err.Error())
+	}
+
+	crng := fastRNG.NewStreamGenerator(100, 5, csprng.NewSystemRNG)
+
+	m := &manager{
+		me:       pi,
+		channels: make(map[id.ID]*joinedChannel),
+		nicknameManager: &nicknameManager{
+			byChannel: make(map[id.ID]string),
+			kv:        nil,
+		},
+		rng: fastRNG.NewStreamGenerator(1000, 10, csprng.NewSystemRNG),
+		st: loadSendTracker(&mockBroadcastClient{},
+			versioned.NewKV(ekv.MakeMemstore()), func(chID *id.ID,
+				umi *userMessageInternal, ts time.Time,
+				receptionID receptionID.EphemeralIdentity,
+				round rounds.Round, status SentStatus) (uint64, error) {
+				return 0, nil
+			}, func(chID *id.ID, cm *ChannelMessage, ts time.Time,
+				messageID cryptoChannel.MessageID, receptionID receptionID.EphemeralIdentity,
+				round rounds.Round, status SentStatus) (uint64, error) {
+				return 0, nil
+			}, func(uuid uint64, messageID cryptoChannel.MessageID,
+				timestamp time.Time, round rounds.Round, status SentStatus) {
+			}, crng),
+	}
+
+	channelID := new(id.ID)
+	messageType := Text
+	msg := "hello world"
+	validUntil := time.Hour
+	params := new(cmix.CMIXParams)
+
+	mbc := &mockBroadcastChannel{}
+
+	m.channels[*channelID] = &joinedChannel{
+		broadcast: mbc,
+	}
+
+	messageId, roundId, ephemeralId, err := m.SendMessage(
+		channelID,
+		msg,
+		validUntil,
+		*params)
+	if err != nil {
+		t.Logf("ERROR %v", err)
+		t.Fail()
+	}
+	t.Logf("messageId %v, roundId %v, ephemeralId %v", messageId, roundId, ephemeralId)
+
+	// verify the message was handled correctly
+
+	// decode the user message
+	umi, err := unmarshalUserMessageInternal(mbc.payload, channelID)
+	if err != nil {
+		t.Fatalf("Failed to decode the user message: %s", err)
+	}
+
+	// do checks of the data
+	if !umi.GetMessageID().Equals(messageId) {
+		t.Errorf("The message IDs do not match. %s vs %s ",
+			umi.messageID, messageId)
+	}
+
+	if MessageType(umi.GetChannelMessage().PayloadType) != messageType {
+		t.Fatalf("Message types do not match, %s vs %s",
+			MessageType(umi.GetChannelMessage().PayloadType), messageType)
+	}
+
+	if umi.GetChannelMessage().RoundID != returnedRound {
+		t.Errorf("The returned round is incorrect, %d vs %d",
+			umi.GetChannelMessage().RoundID, returnedRound)
+	}
+
+	// decode the text message
+	txt := &CMIXChannelText{}
+	err = proto.Unmarshal(umi.GetChannelMessage().Payload, txt)
+	if err != nil {
+		t.Fatalf("Could not decode cmix channel text: %s", err)
+	}
+
+	if txt.Text != msg {
+		t.Errorf("Content of message is incorrect: %s vs %s", txt.Text, msg)
+	}
+
+	if txt.ReplyMessageID != nil {
+		t.Errorf("Reply ID on a text message is not nil")
+	}
+}
+
+func TestSendReply(t *testing.T) {
+
+	prng := rand.New(rand.NewSource(64))
+
+	pi, err := cryptoChannel.GenerateIdentity(prng)
+	if err != nil {
+		t.Fatalf(err.Error())
+	}
+
+	crng := fastRNG.NewStreamGenerator(100, 5, csprng.NewSystemRNG)
+
+	m := &manager{
+		me:       pi,
+		channels: make(map[id.ID]*joinedChannel),
+		nicknameManager: &nicknameManager{
+			byChannel: make(map[id.ID]string),
+			kv:        nil,
+		},
+		rng: fastRNG.NewStreamGenerator(1000, 10, csprng.NewSystemRNG),
+		st: loadSendTracker(&mockBroadcastClient{},
+			versioned.NewKV(ekv.MakeMemstore()), func(chID *id.ID,
+				umi *userMessageInternal, ts time.Time,
+				receptionID receptionID.EphemeralIdentity,
+				round rounds.Round, status SentStatus) (uint64, error) {
+				return 0, nil
+			}, func(chID *id.ID, cm *ChannelMessage, ts time.Time,
+				messageID cryptoChannel.MessageID, receptionID receptionID.EphemeralIdentity,
+				round rounds.Round, status SentStatus) (uint64, error) {
+				return 0, nil
+			}, func(uuid uint64, messageID cryptoChannel.MessageID,
+				timestamp time.Time, round rounds.Round, status SentStatus) {
+			}, crng),
+	}
+
+	channelID := new(id.ID)
+	messageType := Text
+	msg := "hello world"
+	validUntil := time.Hour
+	params := new(cmix.CMIXParams)
+
+	replyMsgID := cryptoChannel.MessageID{}
+	replyMsgID[0] = 69
+
+	mbc := &mockBroadcastChannel{}
+
+	m.channels[*channelID] = &joinedChannel{
+		broadcast: mbc,
+	}
+
+	messageId, roundId, ephemeralId, err := m.SendReply(
+		channelID, msg, replyMsgID, validUntil, *params)
+	if err != nil {
+		t.Logf("ERROR %v", err)
+		t.Fail()
+	}
+	t.Logf("messageId %v, roundId %v, ephemeralId %v", messageId, roundId, ephemeralId)
+
+	// verify the message was handled correctly
+
+	// decode the user message
+	umi, err := unmarshalUserMessageInternal(mbc.payload, channelID)
+	if err != nil {
+		t.Fatalf("Failed to decode the user message: %s", err)
+	}
+
+	// do checks of the data
+	if !umi.GetMessageID().Equals(messageId) {
+		t.Errorf("The message IDs do not match. %s vs %s ",
+			umi.messageID, messageId)
+	}
+
+	if MessageType(umi.GetChannelMessage().PayloadType) != messageType {
+		t.Fatalf("Message types do not match, %s vs %s",
+			MessageType(umi.GetChannelMessage().PayloadType), messageType)
+	}
+
+	if umi.GetChannelMessage().RoundID != returnedRound {
+		t.Errorf("The returned round is incorrect, %d vs %d",
+			umi.GetChannelMessage().RoundID, returnedRound)
+	}
+
+	// decode the text message
+	txt := &CMIXChannelText{}
+	err = proto.Unmarshal(umi.GetChannelMessage().Payload, txt)
+	if err != nil {
+		t.Fatalf("Could not decode cmix channel text: %s", err)
+	}
+
+	if txt.Text != msg {
+		t.Errorf("Content of message is incorrect: %s vs %s", txt.Text, msg)
+	}
+
+	if !bytes.Equal(txt.ReplyMessageID, replyMsgID[:]) {
+		t.Errorf("The reply message ID is not what was passed in")
+	}
+}
+
+func TestSendReaction(t *testing.T) {
+
+	prng := rand.New(rand.NewSource(64))
+
+	pi, err := cryptoChannel.GenerateIdentity(prng)
+	if err != nil {
+		t.Fatalf(err.Error())
+	}
+
+	crng := fastRNG.NewStreamGenerator(100, 5, csprng.NewSystemRNG)
+
+	m := &manager{
+		me: pi,
+		nicknameManager: &nicknameManager{
+			byChannel: make(map[id.ID]string),
+			kv:        nil,
+		},
+		rng:      fastRNG.NewStreamGenerator(1000, 10, csprng.NewSystemRNG),
+		channels: make(map[id.ID]*joinedChannel),
+		st: loadSendTracker(&mockBroadcastClient{},
+			versioned.NewKV(ekv.MakeMemstore()), func(chID *id.ID,
+				umi *userMessageInternal, ts time.Time,
+				receptionID receptionID.EphemeralIdentity,
+				round rounds.Round, status SentStatus) (uint64, error) {
+				return 0, nil
+			}, func(chID *id.ID, cm *ChannelMessage, ts time.Time,
+				messageID cryptoChannel.MessageID, receptionID receptionID.EphemeralIdentity,
+				round rounds.Round, status SentStatus) (uint64, error) {
+				return 0, nil
+			}, func(uuid uint64, messageID cryptoChannel.MessageID,
+				timestamp time.Time, round rounds.Round, status SentStatus) {
+			}, crng),
+	}
+
+	channelID := new(id.ID)
+	messageType := Reaction
+	msg := "🍆"
+	params := new(cmix.CMIXParams)
+
+	replyMsgID := cryptoChannel.MessageID{}
+	replyMsgID[0] = 69
+
+	mbc := &mockBroadcastChannel{}
+
+	m.channels[*channelID] = &joinedChannel{
+		broadcast: mbc,
+	}
+
+	messageId, roundId, ephemeralId, err := m.SendReaction(
+		channelID, msg, replyMsgID, *params)
+	if err != nil {
+		t.Logf("ERROR %v", err)
+		t.Fail()
+	}
+	t.Logf("messageId %v, roundId %v, ephemeralId %v", messageId, roundId, ephemeralId)
+
+	// verify the message was handled correctly
+
+	// decode the user message
+	umi, err := unmarshalUserMessageInternal(mbc.payload, channelID)
+	if err != nil {
+		t.Fatalf("Failed to decode the user message: %s", err)
+	}
+
+	// do checks of the data
+	if !umi.GetMessageID().Equals(messageId) {
+		t.Errorf("The message IDs do not match. %s vs %s ",
+			umi.messageID, messageId)
+	}
+
+	if MessageType(umi.GetChannelMessage().PayloadType) != messageType {
+		t.Fatalf("Message types do not match, %s vs %s",
+			MessageType(umi.GetChannelMessage().PayloadType), messageType)
+	}
+
+	if umi.GetChannelMessage().RoundID != returnedRound {
+		t.Errorf("The returned round is incorrect, %d vs %d",
+			umi.GetChannelMessage().RoundID, returnedRound)
+	}
+
+	// decode the text message
+	txt := &CMIXChannelReaction{}
+	err = proto.Unmarshal(umi.GetChannelMessage().Payload, txt)
+	if err != nil {
+		t.Fatalf("Could not decode cmix channel text: %s", err)
+	}
+
+	if txt.Reaction != msg {
+		t.Errorf("Content of message is incorrect: %s vs %s", txt.Reaction, msg)
+	}
+
+	if !bytes.Equal(txt.ReactionMessageID, replyMsgID[:]) {
+		t.Errorf("The reply message ID is not what was passed in")
+	}
+}
diff --git a/channels/text.pb.go b/channels/text.pb.go
new file mode 100644
index 0000000000000000000000000000000000000000..5eea7e0ed48b0a5decd88d14d002fbf24c03b39a
--- /dev/null
+++ b/channels/text.pb.go
@@ -0,0 +1,259 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file                                                               //
+////////////////////////////////////////////////////////////////////////////////
+
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// 	protoc-gen-go v1.27.1
+// 	protoc        v3.15.6
+// source: text.proto
+
+package channels
+
+import (
+	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+	reflect "reflect"
+	sync "sync"
+)
+
+const (
+	// Verify that this generated code is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+	// Verify that runtime/protoimpl is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+// CMIXChannelText is the payload for sending normal text messages to channels
+// the replyMessageID is nil when it is not a reply
+type CMIXChannelText struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Version        uint32 `protobuf:"varint,1,opt,name=version,proto3" json:"version,omitempty"`
+	Text           string `protobuf:"bytes,2,opt,name=text,proto3" json:"text,omitempty"`
+	ReplyMessageID []byte `protobuf:"bytes,3,opt,name=replyMessageID,proto3" json:"replyMessageID,omitempty"`
+}
+
+func (x *CMIXChannelText) Reset() {
+	*x = CMIXChannelText{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_text_proto_msgTypes[0]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *CMIXChannelText) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*CMIXChannelText) ProtoMessage() {}
+
+func (x *CMIXChannelText) ProtoReflect() protoreflect.Message {
+	mi := &file_text_proto_msgTypes[0]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use CMIXChannelText.ProtoReflect.Descriptor instead.
+func (*CMIXChannelText) Descriptor() ([]byte, []int) {
+	return file_text_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *CMIXChannelText) GetVersion() uint32 {
+	if x != nil {
+		return x.Version
+	}
+	return 0
+}
+
+func (x *CMIXChannelText) GetText() string {
+	if x != nil {
+		return x.Text
+	}
+	return ""
+}
+
+func (x *CMIXChannelText) GetReplyMessageID() []byte {
+	if x != nil {
+		return x.ReplyMessageID
+	}
+	return nil
+}
+
+// CMIXChannelReaction is the payload for reactions. The reaction must be a
+// single emoji and the reactionMessageID must be non nil and a real message
+// in the channel
+type CMIXChannelReaction struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Version           uint32 `protobuf:"varint,1,opt,name=version,proto3" json:"version,omitempty"`
+	Reaction          string `protobuf:"bytes,2,opt,name=reaction,proto3" json:"reaction,omitempty"`
+	ReactionMessageID []byte `protobuf:"bytes,3,opt,name=reactionMessageID,proto3" json:"reactionMessageID,omitempty"`
+}
+
+func (x *CMIXChannelReaction) Reset() {
+	*x = CMIXChannelReaction{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_text_proto_msgTypes[1]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *CMIXChannelReaction) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*CMIXChannelReaction) ProtoMessage() {}
+
+func (x *CMIXChannelReaction) ProtoReflect() protoreflect.Message {
+	mi := &file_text_proto_msgTypes[1]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use CMIXChannelReaction.ProtoReflect.Descriptor instead.
+func (*CMIXChannelReaction) Descriptor() ([]byte, []int) {
+	return file_text_proto_rawDescGZIP(), []int{1}
+}
+
+func (x *CMIXChannelReaction) GetVersion() uint32 {
+	if x != nil {
+		return x.Version
+	}
+	return 0
+}
+
+func (x *CMIXChannelReaction) GetReaction() string {
+	if x != nil {
+		return x.Reaction
+	}
+	return ""
+}
+
+func (x *CMIXChannelReaction) GetReactionMessageID() []byte {
+	if x != nil {
+		return x.ReactionMessageID
+	}
+	return nil
+}
+
+var File_text_proto protoreflect.FileDescriptor
+
+var file_text_proto_rawDesc = []byte{
+	0x0a, 0x0a, 0x74, 0x65, 0x78, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x08, 0x63, 0x68,
+	0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x22, 0x67, 0x0a, 0x0f, 0x43, 0x4d, 0x49, 0x58, 0x43, 0x68,
+	0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x54, 0x65, 0x78, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72,
+	0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73,
+	0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x65, 0x78, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28,
+	0x09, 0x52, 0x04, 0x74, 0x65, 0x78, 0x74, 0x12, 0x26, 0x0a, 0x0e, 0x72, 0x65, 0x70, 0x6c, 0x79,
+	0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x49, 0x44, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52,
+	0x0e, 0x72, 0x65, 0x70, 0x6c, 0x79, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x49, 0x44, 0x22,
+	0x79, 0x0a, 0x13, 0x43, 0x4d, 0x49, 0x58, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x52, 0x65,
+	0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f,
+	0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e,
+	0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01,
+	0x28, 0x09, 0x52, 0x08, 0x72, 0x65, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x2c, 0x0a, 0x11,
+	0x72, 0x65, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x49,
+	0x44, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x11, 0x72, 0x65, 0x61, 0x63, 0x74, 0x69, 0x6f,
+	0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x49, 0x44, 0x42, 0x24, 0x5a, 0x22, 0x67, 0x69,
+	0x74, 0x6c, 0x61, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x65, 0x6c, 0x69, 0x78, 0x78, 0x69, 0x72,
+	0x2f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x2f, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73,
+	0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+}
+
+var (
+	file_text_proto_rawDescOnce sync.Once
+	file_text_proto_rawDescData = file_text_proto_rawDesc
+)
+
+func file_text_proto_rawDescGZIP() []byte {
+	file_text_proto_rawDescOnce.Do(func() {
+		file_text_proto_rawDescData = protoimpl.X.CompressGZIP(file_text_proto_rawDescData)
+	})
+	return file_text_proto_rawDescData
+}
+
+var file_text_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
+var file_text_proto_goTypes = []interface{}{
+	(*CMIXChannelText)(nil),     // 0: channels.CMIXChannelText
+	(*CMIXChannelReaction)(nil), // 1: channels.CMIXChannelReaction
+}
+var file_text_proto_depIdxs = []int32{
+	0, // [0:0] is the sub-list for method output_type
+	0, // [0:0] is the sub-list for method input_type
+	0, // [0:0] is the sub-list for extension type_name
+	0, // [0:0] is the sub-list for extension extendee
+	0, // [0:0] is the sub-list for field type_name
+}
+
+func init() { file_text_proto_init() }
+func file_text_proto_init() {
+	if File_text_proto != nil {
+		return
+	}
+	if !protoimpl.UnsafeEnabled {
+		file_text_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*CMIXChannelText); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_text_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*CMIXChannelReaction); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+	}
+	type x struct{}
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+			RawDescriptor: file_text_proto_rawDesc,
+			NumEnums:      0,
+			NumMessages:   2,
+			NumExtensions: 0,
+			NumServices:   0,
+		},
+		GoTypes:           file_text_proto_goTypes,
+		DependencyIndexes: file_text_proto_depIdxs,
+		MessageInfos:      file_text_proto_msgTypes,
+	}.Build()
+	File_text_proto = out.File
+	file_text_proto_rawDesc = nil
+	file_text_proto_goTypes = nil
+	file_text_proto_depIdxs = nil
+}
diff --git a/channels/text.proto b/channels/text.proto
new file mode 100644
index 0000000000000000000000000000000000000000..26cc59ca76ed8b888b9969730ad9fe2e1fe80d8b
--- /dev/null
+++ b/channels/text.proto
@@ -0,0 +1,29 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file                                                               //
+////////////////////////////////////////////////////////////////////////////////
+
+syntax = "proto3";
+
+option go_package = "gitlab.com/elixxir/client/channels";
+
+package channels;
+
+// CMIXChannelText is the payload for sending normal text messages to channels
+// the replyMessageID is nil when it is not a reply
+message CMIXChannelText {
+  uint32 version = 1;
+  string text = 2;
+  bytes replyMessageID = 3;
+}
+
+// CMIXChannelReaction is the payload for reactions. The reaction must be a
+// single emoji and the reactionMessageID must be non nil and a real message
+// in the channel
+message CMIXChannelReaction {
+  uint32 version = 1;
+  string reaction = 2;
+  bytes reactionMessageID = 3;
+}
\ No newline at end of file
diff --git a/channels/userListener.go b/channels/userListener.go
new file mode 100644
index 0000000000000000000000000000000000000000..dad5075fd08daf0a46f2a221108df2b90dc45a91
--- /dev/null
+++ b/channels/userListener.go
@@ -0,0 +1,80 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file                                                               //
+////////////////////////////////////////////////////////////////////////////////
+
+package channels
+
+import (
+	"crypto/ed25519"
+	jww "github.com/spf13/jwalterweatherman"
+	"gitlab.com/elixxir/client/cmix/identity/receptionID"
+	"gitlab.com/elixxir/client/cmix/rounds"
+	"gitlab.com/elixxir/primitives/states"
+	"gitlab.com/xx_network/primitives/id"
+)
+
+// the userListener adheres to the [broadcast.ListenerFunc] interface and is
+// used when user messages are received on the channel
+type userListener struct {
+	name      NameService
+	chID      *id.ID
+	trigger   triggerEventFunc
+	checkSent messageReceiveFunc
+}
+
+// Listen is called when a message is received for the user listener
+func (ul *userListener) Listen(payload []byte,
+	receptionID receptionID.EphemeralIdentity, round rounds.Round) {
+
+	//Decode the message as a user message
+	umi, err := unmarshalUserMessageInternal(payload, ul.chID)
+	if err != nil {
+		jww.WARN.Printf("Failed to unmarshal User Message on "+
+			"channel %s", ul.chID)
+		return
+	}
+
+	um := umi.GetUserMessage()
+	cm := umi.GetChannelMessage()
+	msgID := umi.GetMessageID()
+
+	//check if we sent the message, ignore triggering if we sent
+	if ul.checkSent(msgID, round) {
+		return
+	}
+
+	/*CRYPTOGRAPHICALLY RELEVANT CHECKS*/
+
+	// check the round to ensure the message is not a replay
+	if id.Round(cm.RoundID) != round.ID {
+		jww.WARN.Printf("The round message %s send on %d referenced "+
+			"(%d) was not the same as the round the message was found on (%d)",
+			msgID, ul.chID, cm.RoundID, round.ID)
+		return
+	}
+
+	// check that the user properly signed the message
+	if !ed25519.Verify(um.ECCPublicKey, um.Message, um.Signature) {
+		jww.WARN.Printf("Message %s on channel %s purportedly from %s "+
+			"failed its user signature with signature %v", msgID,
+			ul.chID, cm.Nickname, um.Signature)
+		return
+	}
+
+	// Modify the timestamp to reduce the chance message order will be ambiguous
+	ts := mutateTimestamp(round.Timestamps[states.QUEUED], msgID)
+
+	//TODO: Processing of the message relative to admin commands will be here
+
+	//Submit the message to the event model for listening
+	if uuid, err := ul.trigger(ul.chID, umi, ts, receptionID, round,
+		Delivered); err != nil {
+		jww.WARN.Printf("Error in passing off trigger for "+
+			"message (UUID: %d): %+v", uuid, err)
+	}
+
+	return
+}
diff --git a/channels/userListener_test.go b/channels/userListener_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..23d8ae8c1188ef7c717680f4b6a980dace81e0cc
--- /dev/null
+++ b/channels/userListener_test.go
@@ -0,0 +1,358 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file                                                               //
+////////////////////////////////////////////////////////////////////////////////
+
+package channels
+
+import (
+	"bytes"
+	"crypto/ed25519"
+	"gitlab.com/xx_network/primitives/netTime"
+	"math/rand"
+	"testing"
+	"time"
+
+	"github.com/golang/protobuf/proto"
+
+	"gitlab.com/elixxir/client/cmix/identity/receptionID"
+	"gitlab.com/elixxir/client/cmix/rounds"
+	cryptoChannel "gitlab.com/elixxir/crypto/channel"
+	"gitlab.com/elixxir/primitives/states"
+	"gitlab.com/xx_network/primitives/id"
+)
+
+type triggerEventDummy struct {
+	gotData bool
+
+	chID        *id.ID
+	umi         *userMessageInternal
+	msgID       cryptoChannel.MessageID
+	receptionID receptionID.EphemeralIdentity
+	round       rounds.Round
+}
+
+func (ted *triggerEventDummy) triggerEvent(chID *id.ID, umi *userMessageInternal,
+	ts time.Time, receptionID receptionID.EphemeralIdentity, round rounds.Round,
+	sent SentStatus) (uint64, error) {
+	ted.gotData = true
+
+	ted.chID = chID
+	ted.umi = umi
+	ted.receptionID = receptionID
+	ted.round = round
+	ted.msgID = umi.GetMessageID()
+
+	return 0, nil
+}
+
+// Tests the happy path
+func TestUserListener_Listen(t *testing.T) {
+
+	//build inputs
+	chID := &id.ID{}
+	chID[0] = 1
+
+	r := rounds.Round{ID: 420, Timestamps: make(map[states.Round]time.Time)}
+	r.Timestamps[states.QUEUED] = netTime.Now()
+
+	rng := rand.New(rand.NewSource(42))
+	pub, priv, err := ed25519.GenerateKey(rng)
+	if err != nil {
+		t.Fatalf("failed to generate ed25519 keypair, cant run test")
+	}
+
+	cm := &ChannelMessage{
+		Lease:       int64(time.Hour),
+		RoundID:     uint64(r.ID),
+		PayloadType: 42,
+		Payload:     []byte("blarg"),
+	}
+
+	cmSerial, err := proto.Marshal(cm)
+	if err != nil {
+		t.Fatalf("Failed to marshal proto: %+v", err)
+	}
+
+	msgID := cryptoChannel.MakeMessageID(cmSerial, chID)
+
+	sig := ed25519.Sign(priv, cmSerial)
+	ns := &mockNameService{validChMsg: true}
+
+	um := &UserMessage{
+		Message:      cmSerial,
+		Signature:    sig,
+		ECCPublicKey: pub,
+	}
+
+	umSerial, err := proto.Marshal(um)
+	if err != nil {
+		t.Fatalf("Failed to marshal proto: %+v", err)
+	}
+
+	//build the listener
+	dummy := &triggerEventDummy{}
+
+	al := userListener{
+		chID:      chID,
+		name:      ns,
+		trigger:   dummy.triggerEvent,
+		checkSent: func(messageID cryptoChannel.MessageID, r rounds.Round) bool { return false },
+	}
+
+	//call the listener
+	al.Listen(umSerial, receptionID.EphemeralIdentity{}, r)
+
+	//check the results
+	if !dummy.gotData {
+		t.Fatalf("No data returned after valid listen")
+	}
+
+	if !dummy.chID.Cmp(chID) {
+		t.Errorf("Channel ID not correct: %s vs %s", dummy.chID, chID)
+	}
+
+	if !bytes.Equal(um.Message, dummy.umi.userMessage.Message) {
+		t.Errorf("message not correct: %s vs %s", um.Message,
+			dummy.umi.userMessage.Message)
+	}
+
+	if !msgID.Equals(dummy.msgID) {
+		t.Errorf("messageIDs not correct: %s vs %s", msgID,
+			dummy.msgID)
+	}
+
+	if r.ID != dummy.round.ID {
+		t.Errorf("rounds not correct: %s vs %s", r.ID,
+			dummy.round.ID)
+	}
+}
+
+//tests that the message is rejected when the user signature is invalid
+func TestUserListener_Listen_BadUserSig(t *testing.T) {
+
+	//build inputs
+	chID := &id.ID{}
+	chID[0] = 1
+
+	r := rounds.Round{ID: 420, Timestamps: make(map[states.Round]time.Time)}
+	r.Timestamps[states.QUEUED] = netTime.Now()
+
+	rng := rand.New(rand.NewSource(42))
+	pub, _, err := ed25519.GenerateKey(rng)
+	if err != nil {
+		t.Fatalf("failed to generate ed25519 keypair, cant run test")
+	}
+
+	cm := &ChannelMessage{
+		Lease:       int64(time.Hour),
+		RoundID:     uint64(r.ID),
+		PayloadType: 42,
+		Payload:     []byte("blarg"),
+	}
+
+	cmSerial, err := proto.Marshal(cm)
+	if err != nil {
+		t.Fatalf("Failed to marshal proto: %+v", err)
+	}
+
+	_, badpriv, err := ed25519.GenerateKey(rng)
+	if err != nil {
+		t.Fatalf("failed to generate ed25519 keypair, cant run test")
+	}
+
+	sig := ed25519.Sign(badpriv, cmSerial)
+	ns := &mockNameService{validChMsg: true}
+
+	um := &UserMessage{
+		Message:      cmSerial,
+		Signature:    sig,
+		ECCPublicKey: pub,
+	}
+
+	umSerial, err := proto.Marshal(um)
+	if err != nil {
+		t.Fatalf("Failed to marshal proto: %+v", err)
+	}
+
+	//build the listener
+	dummy := &triggerEventDummy{}
+
+	al := userListener{
+		chID:      chID,
+		name:      ns,
+		trigger:   dummy.triggerEvent,
+		checkSent: func(messageID cryptoChannel.MessageID, r rounds.Round) bool { return false },
+	}
+
+	//call the listener
+	al.Listen(umSerial, receptionID.EphemeralIdentity{}, r)
+
+	//check the results
+	if dummy.gotData {
+		t.Fatalf("Data returned after invalid listen")
+	}
+}
+
+//tests that the message is rejected when the round in the message does not
+//match the round passed in
+func TestUserListener_Listen_BadRound(t *testing.T) {
+
+	//build inputs
+	chID := &id.ID{}
+	chID[0] = 1
+
+	r := rounds.Round{ID: 420, Timestamps: make(map[states.Round]time.Time)}
+	r.Timestamps[states.QUEUED] = netTime.Now()
+
+	rng := rand.New(rand.NewSource(42))
+	pub, priv, err := ed25519.GenerateKey(rng)
+	if err != nil {
+		t.Fatalf("failed to generate ed25519 keypair, cant run test")
+	}
+
+	cm := &ChannelMessage{
+		Lease: int64(time.Hour),
+		//make the round not match
+		RoundID:     69,
+		PayloadType: 42,
+		Payload:     []byte("blarg"),
+	}
+
+	cmSerial, err := proto.Marshal(cm)
+	if err != nil {
+		t.Fatalf("Failed to marshal proto: %+v", err)
+	}
+
+	sig := ed25519.Sign(priv, cmSerial)
+	ns := &mockNameService{validChMsg: true}
+
+	um := &UserMessage{
+		Message:      cmSerial,
+		Signature:    sig,
+		ECCPublicKey: pub,
+	}
+
+	umSerial, err := proto.Marshal(um)
+	if err != nil {
+		t.Fatalf("Failed to marshal proto: %+v", err)
+	}
+
+	//build the listener
+	dummy := &triggerEventDummy{}
+
+	al := userListener{
+		chID:      chID,
+		name:      ns,
+		trigger:   dummy.triggerEvent,
+		checkSent: func(messageID cryptoChannel.MessageID, r rounds.Round) bool { return false },
+	}
+
+	//call the listener
+	al.Listen(umSerial, receptionID.EphemeralIdentity{}, r)
+
+	//check the results
+	if dummy.gotData {
+		t.Fatalf("Data returned after invalid listen")
+	}
+}
+
+//tests that the message is rejected when the user message is malformed
+func TestUserListener_Listen_BadMessage(t *testing.T) {
+
+	//build inputs
+	chID := &id.ID{}
+	chID[0] = 1
+
+	r := rounds.Round{ID: 420, Timestamps: make(map[states.Round]time.Time)}
+	r.Timestamps[states.QUEUED] = netTime.Now()
+
+	ns := &mockNameService{validChMsg: true}
+
+	umSerial := []byte("malformed")
+
+	//build the listener
+	dummy := &triggerEventDummy{}
+
+	al := userListener{
+		chID:      chID,
+		name:      ns,
+		trigger:   dummy.triggerEvent,
+		checkSent: func(messageID cryptoChannel.MessageID, r rounds.Round) bool { return false },
+	}
+
+	//call the listener
+	al.Listen(umSerial, receptionID.EphemeralIdentity{}, r)
+
+	//check the results
+	if dummy.gotData {
+		t.Fatalf("Data returned after invalid listen")
+	}
+}
+
+//tests that the message is rejected when the sized broadcast is malformed
+func TestUserListener_Listen_BadSizedBroadcast(t *testing.T) {
+
+	//build inputs
+	chID := &id.ID{}
+	chID[0] = 1
+
+	r := rounds.Round{ID: 420, Timestamps: make(map[states.Round]time.Time)}
+	r.Timestamps[states.QUEUED] = netTime.Now()
+
+	rng := rand.New(rand.NewSource(42))
+	pub, priv, err := ed25519.GenerateKey(rng)
+	if err != nil {
+		t.Fatalf("failed to generate ed25519 keypair, cant run test")
+	}
+
+	cm := &ChannelMessage{
+		Lease: int64(time.Hour),
+		//make the round not match
+		RoundID:     69,
+		PayloadType: 42,
+		Payload:     []byte("blarg"),
+	}
+
+	cmSerial, err := proto.Marshal(cm)
+	if err != nil {
+		t.Fatalf("Failed to marshal proto: %+v", err)
+	}
+
+	sig := ed25519.Sign(priv, cmSerial)
+	ns := &mockNameService{validChMsg: true}
+
+	um := &UserMessage{
+		Message:      cmSerial,
+		Signature:    sig,
+		ECCPublicKey: pub,
+	}
+
+	umSerial, err := proto.Marshal(um)
+	if err != nil {
+		t.Fatalf("Failed to marshal proto: %+v", err)
+	}
+
+	//remove half the sized broadcast to make it malformed
+	umSerial = umSerial[:len(umSerial)/2]
+
+	//build the listener
+	dummy := &triggerEventDummy{}
+
+	al := userListener{
+		chID:      chID,
+		name:      ns,
+		trigger:   dummy.triggerEvent,
+		checkSent: func(messageID cryptoChannel.MessageID, r rounds.Round) bool { return false },
+	}
+
+	//call the listener
+	al.Listen(umSerial, receptionID.EphemeralIdentity{}, r)
+
+	//check the results
+	if dummy.gotData {
+		t.Fatalf("Data returned after invalid listen")
+	}
+}
diff --git a/cmd/backup.go b/cmd/backup.go
index a102a56570c4cce0256de12d2c29f4d2d8814a14..91cc194d71596ce22601dddb333fff6f24742bfd 100644
--- a/cmd/backup.go
+++ b/cmd/backup.go
@@ -1,7 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2022 Privategrity Corporation                                   /
-//                                                                             /
-// All rights reserved.                                                        /
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package cmd
diff --git a/cmd/broadcast.go b/cmd/broadcast.go
index f6487332c36daab637b48435717ef2b65255c9ee..7b0e7c9183ae1311bf7f2478640309723ca824e4 100644
--- a/cmd/broadcast.go
+++ b/cmd/broadcast.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package cmd
 
 import (
@@ -13,7 +20,7 @@ import (
 	"gitlab.com/elixxir/client/cmix/identity/receptionID"
 	"gitlab.com/elixxir/client/cmix/rounds"
 	crypto "gitlab.com/elixxir/crypto/broadcast"
-	"gitlab.com/xx_network/crypto/signature/rsa"
+	rsa2 "gitlab.com/elixxir/crypto/rsa"
 	"gitlab.com/xx_network/primitives/utils"
 	"sync"
 )
@@ -49,7 +56,7 @@ var broadcastCmd = &cobra.Command{
 		waitUntilConnected(connected)
 		/* Set up underlying crypto broadcast.Channel */
 		var channel *crypto.Channel
-		var pk *rsa.PrivateKey
+		var pk rsa2.PrivateKey
 		keyPath := viper.GetString(broadcastKeyPathFlag)
 		path, err := utils.ExpandPath(viper.GetString(broadcastChanPathFlag))
 		if utils.Exists(path) {
@@ -74,23 +81,25 @@ var broadcastCmd = &cobra.Command{
 
 			if viper.GetBool(broadcastNewFlag) {
 				// Create a new broadcast channel
-				channel, pk, err = crypto.NewChannel(name, desc, user.GetRng().GetStream())
+				channel, pk, err = crypto.NewChannel(name, desc, user.GetCmix().GetMaxMessageLength(), user.GetRng().GetStream())
 				if err != nil {
 					jww.FATAL.Panicf("Failed to create new channel: %+v", err)
 				}
 
 				if keyPath != "" {
-					err = utils.WriteFile(keyPath, rsa.CreatePrivateKeyPem(pk), os.ModePerm, os.ModeDir)
+					err = utils.WriteFile(keyPath, pk.MarshalPem(), os.ModePerm, os.ModeDir)
 					if err != nil {
 						jww.ERROR.Printf("Failed to write private key to path %s: %+v", path, err)
 					}
 				} else {
-					fmt.Printf("Private key generated for channel: %+v", rsa.CreatePrivateKeyPem(pk))
+					fmt.Printf("Private key generated for channel: %+v", pk.MarshalPem())
 				}
 				fmt.Printf("New broadcast channel generated")
 			} else {
+				//fixme: redo channels, should be using pretty print over cli
+
 				// Read rest of info from config & build object manually
-				pubKeyBytes := []byte(viper.GetString(broadcastRsaPubFlag))
+				/*pubKeyBytes := []byte(viper.GetString(broadcastRsaPubFlag))
 				pubKey, err := rsa.LoadPublicKeyFromPem(pubKeyBytes)
 				if err != nil {
 					jww.FATAL.Panicf("Failed to load public key at path: %+v", err)
@@ -108,7 +117,7 @@ var broadcastCmd = &cobra.Command{
 					Description: desc,
 					Salt:        salt,
 					RsaPubKey:   pubKey,
-				}
+				}*/
 			}
 
 			// Save channel to disk
@@ -135,7 +144,8 @@ var broadcastCmd = &cobra.Command{
 				if err != nil {
 					jww.ERROR.Printf("Failed to read private key from %s: %+v", ep, err)
 				}
-				pk, err = rsa.LoadPrivateKeyFromPem(keyBytes)
+
+				pk, err = rsa2.GetScheme().UnmarshalPrivateKeyPEM(keyBytes)
 				if err != nil {
 					jww.ERROR.Printf("Failed to load private key %+v: %+v", keyBytes, err)
 				}
@@ -151,7 +161,7 @@ var broadcastCmd = &cobra.Command{
 		asymmetric := viper.GetString(broadcastAsymmetricFlag)
 
 		// Connect to broadcast channel
-		bcl, err := broadcast.NewBroadcastChannel(*channel, user.GetCmix(), user.GetRng())
+		bcl, err := broadcast.NewBroadcastChannel(channel, user.GetCmix(), user.GetRng())
 
 		// Create & register symmetric receiver callback
 		receiveChan := make(chan []byte, 100)
@@ -172,7 +182,7 @@ var broadcastCmd = &cobra.Command{
 			jww.INFO.Printf("Received asymmetric message from %s over round %d", receptionID, round.ID)
 			asymmetricReceiveChan <- payload
 		}
-		err = bcl.RegisterListener(acb, broadcast.Asymmetric)
+		err = bcl.RegisterListener(acb, broadcast.RSAToPublic)
 		if err != nil {
 			jww.FATAL.Panicf("Failed to register asymmetric listener: %+v", err)
 		}
@@ -198,39 +208,30 @@ var broadcastCmd = &cobra.Command{
 
 					/* Send symmetric broadcast */
 					if symmetric != "" {
-						// Create properly sized broadcast message
-						broadcastMessage, err := broadcast.NewSizedBroadcast(bcl.MaxPayloadSize(), []byte(symmetric))
-						if err != nil {
-							jww.FATAL.Panicf("Failed to create sized broadcast: %+v", err)
-						}
-						rid, eid, err := bcl.Broadcast(broadcastMessage, cmix.GetDefaultCMIXParams())
+						rid, eid, err := bcl.Broadcast([]byte(symmetric), cmix.GetDefaultCMIXParams())
 						if err != nil {
 							jww.ERROR.Printf("Failed to send symmetric broadcast message: %+v", err)
 							retries++
 							continue
 						}
 						fmt.Printf("Sent symmetric broadcast message: %s", symmetric)
-						jww.INFO.Printf("Sent symmetric broadcast message to %s over round %d", eid, rid)
+						jww.INFO.Printf("Sent symmetric broadcast message to %s over round %d", eid, rid.ID)
 					}
 
 					/* Send asymmetric broadcast */
 					if asymmetric != "" {
 						// Create properly sized broadcast message
-						broadcastMessage, err := broadcast.NewSizedBroadcast(bcl.MaxAsymmetricPayloadSize(), []byte(asymmetric))
-						if err != nil {
-							jww.FATAL.Panicf("Failed to create sized broadcast: %+v", err)
-						}
 						if pk == nil {
 							jww.FATAL.Panicf("CANNOT SEND ASYMMETRIC BROADCAST WITHOUT PRIVATE KEY")
 						}
-						rid, eid, err := bcl.BroadcastAsymmetric(pk, broadcastMessage, cmix.GetDefaultCMIXParams())
+						rid, eid, err := bcl.BroadcastRSAtoPublic(pk, []byte(asymmetric), cmix.GetDefaultCMIXParams())
 						if err != nil {
 							jww.ERROR.Printf("Failed to send asymmetric broadcast message: %+v", err)
 							retries++
 							continue
 						}
 						fmt.Printf("Sent asymmetric broadcast message: %s", asymmetric)
-						jww.INFO.Printf("Sent asymmetric broadcast message to %s over round %d", eid, rid)
+						jww.INFO.Printf("Sent asymmetric broadcast message to %s over round %d", eid, rid.ID)
 					}
 
 					wg.Done()
@@ -254,23 +255,13 @@ var broadcastCmd = &cobra.Command{
 			select {
 			case receivedPayload := <-asymmetricReceiveChan:
 				receivedCount++
-				receivedBroadcast, err := broadcast.DecodeSizedBroadcast(receivedPayload)
-				if err != nil {
-					jww.ERROR.Printf("Failed to decode sized broadcast: %+v", err)
-					continue
-				}
-				fmt.Printf("Asymmetric broadcast message received: %s\n", string(receivedBroadcast))
+				fmt.Printf("Asymmetric broadcast message received: %s\n", string(receivedPayload))
 				if receivedCount == expectedCnt {
 					done = true
 				}
 			case receivedPayload := <-receiveChan:
 				receivedCount++
-				receivedBroadcast, err := broadcast.DecodeSizedBroadcast(receivedPayload)
-				if err != nil {
-					jww.ERROR.Printf("Failed to decode sized broadcast: %+v", err)
-					continue
-				}
-				fmt.Printf("Symmetric broadcast message received: %s\n", string(receivedBroadcast))
+				fmt.Printf("Symmetric broadcast message received: %s\n", string(receivedPayload))
 				if receivedCount == expectedCnt {
 					done = true
 				}
diff --git a/cmd/callbacks.go b/cmd/callbacks.go
index df834ca48f115eeecb34350e5897caa8bb79fa0a..058c79dd0430b81243a4077f167694b37a909c3d 100644
--- a/cmd/callbacks.go
+++ b/cmd/callbacks.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 // callbacks.go implements all of the required api callbacks for the cli
 package cmd
@@ -27,6 +27,7 @@ import (
 type authCallbacks struct {
 	autoConfirm bool
 	confCh      chan *id.ID
+	reqCh       chan *id.ID
 	params      xxdk.E2EParams
 }
 
@@ -34,6 +35,7 @@ func makeAuthCallbacks(autoConfirm bool, params xxdk.E2EParams) *authCallbacks {
 	return &authCallbacks{
 		autoConfirm: autoConfirm,
 		confCh:      make(chan *id.ID, 10),
+		reqCh:       make(chan *id.ID, 10),
 		params:      params,
 	}
 }
@@ -44,7 +46,7 @@ func (a *authCallbacks) Request(requestor contact.Contact,
 	msg := fmt.Sprintf("Authentication channel request from: %s\n",
 		requestor.ID)
 	jww.INFO.Printf(msg)
-	fmt.Printf(msg)
+	fmt.Print(msg)
 	if a.autoConfirm {
 		jww.INFO.Printf("Channel Request: %s",
 			requestor.ID)
@@ -55,8 +57,9 @@ func (a *authCallbacks) Request(requestor contact.Contact,
 		}
 
 		a.confCh <- requestor.ID
+	} else {
+		a.reqCh <- requestor.ID
 	}
-
 }
 
 func (a *authCallbacks) Confirm(requestor contact.Contact,
@@ -72,7 +75,7 @@ func (a *authCallbacks) Reset(requestor contact.Contact,
 	msg := fmt.Sprintf("Authentication channel reset from: %s\n",
 		requestor.ID)
 	jww.INFO.Printf(msg)
-	fmt.Printf(msg)
+	fmt.Print(msg)
 }
 
 func registerMessageListener(user *xxdk.E2e) chan receive.Message {
diff --git a/cmd/connect.go b/cmd/connect.go
index e8697dc60b8f0b5181df175274e12e881ce12b78..67059fc616f6f05658b180ef68142e08421abbdf 100644
--- a/cmd/connect.go
+++ b/cmd/connect.go
@@ -1,8 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2022 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package cmd
@@ -486,7 +486,7 @@ func miscConnectionFunctions(user *xxdk.E2e, conn connect.Connection) {
 			conn.GetPartner().PartnerId())
 		payload := []byte(msgBody)
 		for {
-			roundIDs, _, _, err := conn.SendE2E(catalog.XxMessage, payload,
+			sendReport, err := conn.SendE2E(catalog.XxMessage, payload,
 				paramsE2E)
 			if err != nil {
 				jww.FATAL.Panicf("[CONN] Failed to send E2E message: %v", err)
@@ -494,7 +494,7 @@ func miscConnectionFunctions(user *xxdk.E2e, conn connect.Connection) {
 
 			// Verify message sends were successful when verifySendFlag is present
 			if viper.GetBool(verifySendFlag) {
-				if !verifySendSuccess(user, paramsE2E, roundIDs,
+				if !verifySendSuccess(user, paramsE2E, sendReport.RoundList,
 					conn.GetPartner().PartnerId(), payload) {
 					continue
 				}
diff --git a/cmd/deployment.go b/cmd/deployment.go
index f5350d516b2beff594fae0d0f70568c3318c2484..8e22630ee0d11da8737910859165683da0004e6c 100644
--- a/cmd/deployment.go
+++ b/cmd/deployment.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2022 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package cmd
 
diff --git a/cmd/dumpRounds.go b/cmd/dumpRounds.go
index 88743972921640bc169fd7213122e07254af77b0..b7e8daf14ef5d7be1f67a7c8ab2f2d2e5f1f11e7 100644
--- a/cmd/dumpRounds.go
+++ b/cmd/dumpRounds.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 // Package cmd initializes the CLI and config parsers as well as the logger.
 package cmd
diff --git a/cmd/fileTransfer.go b/cmd/fileTransfer.go
index 1b0e2fe5c79da6c8f5d8494e7b9d2b618a0f83d0..dbe42e5cdea1bfe94bed39090f08e37f297386c8 100644
--- a/cmd/fileTransfer.go
+++ b/cmd/fileTransfer.go
@@ -1,8 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package cmd
diff --git a/cmd/flags.go b/cmd/flags.go
index 93b5d505d77f4846f80d1cda6b32bfa29a0ad3cf..5406561ba70cade7dd1cd260ee5d12c4d55b8283 100644
--- a/cmd/flags.go
+++ b/cmd/flags.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2022 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package cmd
 
@@ -80,7 +80,9 @@ const (
 	// Misc
 	sendIdFlag       = "sendid"
 	profileCpuFlag   = "profile-cpu"
+	profileMemFlag   = "profile-mem"
 	userIdPrefixFlag = "userid-prefix"
+	legacyFlag       = "legacy"
 
 	///////////////// Broadcast subcommand flags //////////////////////////////
 	broadcastNameFlag        = "name"
diff --git a/cmd/getndf.go b/cmd/getndf.go
index 8a107960597d96e163e2d5d0963b3c6291e51113..b94540bbdfb6b3ad6a74ff86d5ffa0f6384aad32 100644
--- a/cmd/getndf.go
+++ b/cmd/getndf.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 // Package cmd initializes the CLI and config parsers as well as the logger.
 package cmd
diff --git a/cmd/group.go b/cmd/group.go
index 1c1b1f72159371aaf85851acb627184dfb2abcfd..0cf296b4cca2bdc8f2206eb40b4a15367df3a167 100644
--- a/cmd/group.go
+++ b/cmd/group.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 // The group subcommand allows creation and sending messages to groups
 
@@ -237,7 +237,7 @@ func sendGroup(groupIdString string, msg []byte, gm groupChat.GroupChat) {
 	}
 
 	jww.INFO.Printf("[GC] Sent to group %s on round %d at %s",
-		groupID, rid, timestamp)
+		groupID, rid.ID, timestamp)
 	fmt.Printf("Sent message %q to group.\n", msg)
 }
 
diff --git a/cmd/init.go b/cmd/init.go
index e78ef22bb78387d64210e9d7365bc76fa765fd94..deef974a0a0a4a98069dfbd26a8a01fecb73437d 100644
--- a/cmd/init.go
+++ b/cmd/init.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 // Package cmd initializes the CLI and config parsers as well as the logger.
 package cmd
@@ -45,16 +45,27 @@ var initCmd = &cobra.Command{
 			jww.FATAL.Panicf("%+v", err)
 		}
 
-		identity, err := xxdk.MakeReceptionIdentity(net)
+		// Generate identity
+		var identity xxdk.ReceptionIdentity
+		if viper.GetBool(legacyFlag) {
+			identity, err = xxdk.MakeLegacyReceptionIdentity(net)
+		} else {
+			identity, err = xxdk.MakeReceptionIdentity(net)
+
+		}
+
+		// Panic if conditional branch fails
 		if err != nil {
 			jww.FATAL.Panicf("%+v", err)
 		}
 
+		// Store identity
 		err = xxdk.StoreReceptionIdentity(identityStorageKey, identity, net)
 		if err != nil {
 			jww.FATAL.Panicf("%+v", err)
 		}
 
+		// Write contact to file
 		jww.INFO.Printf("User: %s", identity.ID)
 		writeContact(identity.GetContact())
 
@@ -68,6 +79,11 @@ func init() {
 		"Desired prefix of userID to brute force when running init command. Prepend (?i) for case-insensitive. Only Base64 characters are valid.")
 	bindFlagHelper(userIdPrefixFlag, initCmd)
 
+	initCmd.Flags().BoolP(legacyFlag, "", false,
+		"Generates a legacy identity if set. "+
+			"If this flag is absent, a standard identity will be generated.")
+	bindFlagHelper(legacyFlag, initCmd)
+
 	rootCmd.AddCommand(initCmd)
 }
 
diff --git a/cmd/pickup.go b/cmd/pickup.go
index ee4afbe53c923e9ec864e6a5b20536fe91b78a01..d1171e7a4e044bca1fc55450c8c304019c269ede 100644
--- a/cmd/pickup.go
+++ b/cmd/pickup.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 // Package cmd initializes the CLI and config parsers as well as the logger.
 package cmd
diff --git a/cmd/precan.go b/cmd/precan.go
index 4f607c6b110321da890c6d23851f23b235cb452c..824b17d3a838caa05dfee5a794ee0d0bfa5a90ee 100644
--- a/cmd/precan.go
+++ b/cmd/precan.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 // precan.go handles functions for precan users, which are not usable
 // unless you are on a localized test network.
diff --git a/cmd/proto.go b/cmd/proto.go
index 129ff1b0884eed4b4eacad6454f80c515eb2d53c..0203d1e5f49d81f71204c1ceafdb1c31900a38df 100644
--- a/cmd/proto.go
+++ b/cmd/proto.go
@@ -1,7 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2022 Privategrity Corporation                                   /
-//                                                                             /
-// All rights reserved.                                                        /
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package cmd
diff --git a/cmd/root.go b/cmd/root.go
index 837b68e1af7d13f8476844c3bb0f525be4bcbd63..81d197451d72494298a87613c71ec24a44c86d5f 100644
--- a/cmd/root.go
+++ b/cmd/root.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 // Package cmd initializes the CLI and config parsers as well as the logger.
 package cmd
@@ -17,7 +17,11 @@ import (
 	"io/ioutil"
 	"log"
 	"os"
-	"runtime/pprof"
+
+	cryptoE2e "gitlab.com/elixxir/crypto/e2e"
+
+	"github.com/pkg/profile"
+
 	"strconv"
 	"strings"
 	"sync"
@@ -58,19 +62,28 @@ var rootCmd = &cobra.Command{
 	Short: "Runs a client for cMix anonymous communication platform",
 	Args:  cobra.NoArgs,
 	Run: func(cmd *cobra.Command, args []string) {
-		profileOut := viper.GetString(profileCpuFlag)
-		if profileOut != "" {
-			f, err := os.Create(profileOut)
-			if err != nil {
-				jww.FATAL.Panicf("%+v", err)
-			}
-			pprof.StartCPUProfile(f)
+		cpuProfileOut := viper.GetString(profileCpuFlag)
+		if cpuProfileOut != "" {
+			defer profile.Start(profile.CPUProfile,
+				profile.ProfilePath(cpuProfileOut),
+				profile.NoShutdownHook).Stop()
+		}
+		memProfileOut := viper.GetString(profileMemFlag)
+		if memProfileOut != "" {
+			defer profile.Start(profile.MemProfile,
+				profile.ProfilePath(memProfileOut),
+				profile.NoShutdownHook).Stop()
 		}
 
 		cmixParams, e2eParams := initParams()
 
-		authCbs := makeAuthCallbacks(
-			viper.GetBool(unsafeChannelCreationFlag), e2eParams)
+		autoConfirm := viper.GetBool(unsafeChannelCreationFlag)
+		acceptChannels := viper.GetBool(acceptChannelFlag)
+		if acceptChannels {
+			autoConfirm = false
+		}
+
+		authCbs := makeAuthCallbacks(autoConfirm, e2eParams)
 		user := initE2e(cmixParams, e2eParams, authCbs)
 
 		jww.INFO.Printf("Client Initialized...")
@@ -89,12 +102,14 @@ var rootCmd = &cobra.Command{
 			recipientContact = readContact(destFile)
 			recipientID = recipientContact.ID
 		} else if destId == "0" || sendId == destId {
-			jww.INFO.Printf("Sending message to self")
+			jww.INFO.Printf("Sending message to self, " +
+				"this will timeout unless authrequest is sent")
 			recipientID = receptionIdentity.ID
 			recipientContact = receptionIdentity.GetContact()
 		} else {
 			recipientID = parseRecipient(destId)
-			jww.INFO.Printf("destId: %v\nrecipientId: %v", destId, recipientID)
+			jww.INFO.Printf("destId: %v\nrecipientId: %v", destId,
+				recipientID)
 
 		}
 		isPrecanPartner := isPrecanID(recipientID)
@@ -144,11 +159,42 @@ var rootCmd = &cobra.Command{
 
 		// Send Messages
 		msgBody := viper.GetString(messageFlag)
+		hasMsgs := true
+		if msgBody == "" {
+			hasMsgs = false
+		}
 		time.Sleep(10 * time.Second)
 
 		// Accept auth request for this recipient
+		authSecs := viper.GetUint(authTimeoutFlag)
 		authConfirmed := false
-		if viper.GetBool(acceptChannelFlag) {
+		jww.INFO.Printf("Preexisting E2e partners: %+v", user.GetE2E().GetAllPartnerIDs())
+		if user.GetE2E().HasAuthenticatedChannel(recipientID) {
+			jww.INFO.Printf("Authenticated channel already in "+
+				"place for %s", recipientID)
+			authConfirmed = true
+		} else {
+			jww.INFO.Printf("No authenticated channel in "+
+				"place for %s", recipientID)
+		}
+
+		if acceptChannels && !authConfirmed {
+			for reqDone := false; !reqDone; {
+				select {
+				case reqID := <-authCbs.reqCh:
+					if recipientID.Cmp(reqID) {
+						reqDone = true
+					} else {
+						fmt.Printf(
+							"unexpected request:"+
+								" %s", reqID)
+					}
+				case <-time.After(time.Duration(authSecs) *
+					time.Second):
+					fmt.Print("timed out on auth request")
+					reqDone = true
+				}
+			}
 			// Verify that the confirmation message makes it to the
 			// original sender
 			if viper.GetBool(verifySendFlag) {
@@ -164,16 +210,6 @@ var rootCmd = &cobra.Command{
 			authConfirmed = true
 		}
 
-		jww.INFO.Printf("Preexisting E2e partners: %+v", user.GetE2E().GetAllPartnerIDs())
-		if user.GetE2E().HasAuthenticatedChannel(recipientID) {
-			jww.INFO.Printf("Authenticated channel already in "+
-				"place for %s", recipientID)
-			authConfirmed = true
-		} else {
-			jww.INFO.Printf("No authenticated channel in "+
-				"place for %s", recipientID)
-		}
-
 		// Send unsafe messages or not?
 		unsafe := viper.GetBool(unsafeFlag)
 		sendAuthReq := viper.GetBool(sendAuthRequestFlag)
@@ -193,7 +229,7 @@ var rootCmd = &cobra.Command{
 			authConfirmed = false
 		}
 
-		if !unsafe && !authConfirmed {
+		if !unsafe && !authConfirmed && hasMsgs {
 			// Signal for authConfirm callback in a separate thread
 			go func() {
 				for {
@@ -209,16 +245,15 @@ var rootCmd = &cobra.Command{
 			scnt := uint(0)
 
 			// Wait until authConfirmed
-			waitSecs := viper.GetUint(authTimeoutFlag)
-			for !authConfirmed && scnt < waitSecs {
+			for !authConfirmed && scnt < authSecs {
 				time.Sleep(1 * time.Second)
 				scnt++
 			}
-			if scnt == waitSecs {
+			if scnt == authSecs {
 				jww.FATAL.Panicf("Could not confirm "+
 					"authentication channel for %s, "+
 					"waited %d seconds.", recipientID,
-					waitSecs)
+					authSecs)
 			}
 			jww.INFO.Printf("Authentication channel confirmation"+
 				" took %d seconds", scnt)
@@ -271,6 +306,13 @@ var rootCmd = &cobra.Command{
 
 		wg := &sync.WaitGroup{}
 		sendCnt := int(viper.GetUint(sendCountFlag))
+		if !hasMsgs && sendCnt != 0 {
+			msg := "No message to send, please set your message" +
+				"or set sendCount to 0 to suppress this warning"
+			jww.WARN.Printf(msg)
+			fmt.Print(msg)
+			sendCnt = 0
+		}
 		wg.Add(sendCnt)
 		go func() {
 			sendDelay := time.Duration(viper.GetUint(sendDelayFlag))
@@ -288,8 +330,10 @@ var rootCmd = &cobra.Command{
 								e2eParams.Base)
 						} else {
 							e2eParams.Base.DebugTag = "cmd.E2E"
-							roundIDs, _, _, err = user.GetE2E().SendE2E(mt,
+							var sendReport cryptoE2e.SendReport
+							sendReport, err = user.GetE2E().SendE2E(mt,
 								recipient, payload, e2eParams.Base)
+							roundIDs = sendReport.RoundList
 						}
 						if err != nil {
 							jww.FATAL.Panicf("%+v", err)
@@ -382,9 +426,6 @@ var rootCmd = &cobra.Command{
 				"Failed to cleanly close threads: %+v\n",
 				err)
 		}
-		if profileOut != "" {
-			pprof.StopCPUProfile()
-		}
 		jww.INFO.Printf("Client exiting!")
 	},
 }
@@ -550,7 +591,7 @@ func addAuthenticatedChannel(user *xxdk.E2e, recipientID *id.ID,
 	msg := fmt.Sprintf("Adding authenticated channel for: %s\n",
 		recipientID)
 	jww.INFO.Printf(msg)
-	fmt.Printf(msg)
+	fmt.Print(msg)
 
 	recipientContact := recipient
 
@@ -630,14 +671,8 @@ func acceptChannelVerified(user *xxdk.E2e, recipientID *id.ID,
 		rid := acceptChannel(user, recipientID)
 
 		// Monitor rounds for results
-		err := user.GetCmix().GetRoundResults(roundTimeout,
+		user.GetCmix().GetRoundResults(roundTimeout,
 			makeVerifySendsCallback(retryChan, done), rid)
-		if err != nil {
-			jww.DEBUG.Printf("Could not verify "+
-				"confirmation message for relationship with %s were sent "+
-				"successfully, resending messages...", recipientID)
-			continue
-		}
 
 		select {
 		case <-retryChan:
@@ -671,14 +706,9 @@ func requestChannelVerified(user *xxdk.E2e,
 		}
 
 		// Monitor rounds for results
-		err = user.GetCmix().GetRoundResults(roundTimeout,
+		user.GetCmix().GetRoundResults(roundTimeout,
 			makeVerifySendsCallback(retryChan, done),
 			rid)
-		if err != nil {
-			jww.DEBUG.Printf("Could not verify auth request was sent " +
-				"successfully, resending...")
-			continue
-		}
 
 		select {
 		case <-retryChan:
@@ -710,14 +740,9 @@ func resetChannelVerified(user *xxdk.E2e, recipientContact contact.Contact,
 		}
 
 		// Monitor rounds for results
-		err = user.GetCmix().GetRoundResults(roundTimeout,
+		user.GetCmix().GetRoundResults(roundTimeout,
 			makeVerifySendsCallback(retryChan, done),
 			rid)
-		if err != nil {
-			jww.DEBUG.Printf("Could not verify auth request was sent " +
-				"successfully, resending...")
-			continue
-		}
 
 		select {
 		case <-retryChan:
@@ -1101,6 +1126,10 @@ func init() {
 		"Enable cpu profiling to this file")
 	viper.BindPFlag(profileCpuFlag, rootCmd.Flags().Lookup(profileCpuFlag))
 
+	rootCmd.Flags().String(profileMemFlag, "",
+		"Enable memory profiling to this file")
+	viper.BindPFlag(profileMemFlag, rootCmd.Flags().Lookup(profileMemFlag))
+
 	// Proto user flags
 	rootCmd.Flags().String(protoUserPathFlag, "",
 		"Path to proto user JSON file containing cryptographic primitives "+
diff --git a/cmd/single.go b/cmd/single.go
index 9493840752aa2e9fc97f8fb416d189c43d72e8c9..a8d45e57bb143497ff179d9d9d78f167e7f7fcc4 100644
--- a/cmd/single.go
+++ b/cmd/single.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 // Package cmd initializes the CLI and config parsers as well as the logger.
 package cmd
diff --git a/cmd/ud.go b/cmd/ud.go
index 73a47f02d60e32f588fa1e0f24395a082c23d689..2877615046282534aa506b569c5ea5cc9de066ce 100644
--- a/cmd/ud.go
+++ b/cmd/ud.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 // Package cmd initializes the CLI and config parsers as well as the logger.
 package cmd
@@ -11,7 +11,6 @@ package cmd
 import (
 	"fmt"
 	"gitlab.com/elixxir/client/xxdk"
-	"gitlab.com/elixxir/crypto/cyclic"
 	"gitlab.com/xx_network/primitives/id"
 	"time"
 
@@ -252,8 +251,7 @@ var udCmd = &cobra.Command{
 // to contact UD.
 func getUdContactInfo(user *xxdk.E2e) (cert, contactFile []byte, address string, err error) {
 	// Retrieve address
-	address = string([]byte(user.GetCmix().GetInstance().GetPartialNdf().
-		Get().UDB.Address))
+	address = user.GetCmix().GetInstance().GetPartialNdf().Get().UDB.Address
 
 	// Retrieve certificate
 	cert = []byte(user.GetCmix().GetInstance().GetPartialNdf().Get().UDB.Cert)
@@ -267,7 +265,7 @@ func getUdContactInfo(user *xxdk.E2e) (cert, contactFile []byte, address string,
 
 	// Retrieve DH Pub Key
 	udDhPubKeyData := user.GetCmix().GetInstance().GetPartialNdf().Get().UDB.DhPubKey
-	var udDhPubKey *cyclic.Int
+	udDhPubKey := user.GetE2E().GetGroup().NewInt(1)
 	err = udDhPubKey.UnmarshalJSON(udDhPubKeyData)
 	if err != nil {
 		return nil, nil, "", err
diff --git a/cmd/utils.go b/cmd/utils.go
index 80c9471f4b2124ab2743cf11b72da0d6e41d57e5..ad6de14de40c1b265dca23bb9b996c0e8f4b5e9d 100644
--- a/cmd/utils.go
+++ b/cmd/utils.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package cmd
 
 import (
@@ -46,13 +53,8 @@ func verifySendSuccess(user *xxdk.E2e, paramsE2E e2e.Params,
 	}
 
 	// Monitor rounds for results
-	err := user.GetCmix().GetRoundResults(
+	user.GetCmix().GetRoundResults(
 		paramsE2E.CMIXParams.Timeout, f, roundIDs...)
-	if err != nil {
-		jww.DEBUG.Printf("Could not verify messages were sent " +
-			"successfully, resending messages...")
-		return false
-	}
 
 	select {
 	case <-retryChan:
diff --git a/cmd/version.go b/cmd/version.go
index 41055fef35186085ee0747b89bc17332b13a95df..328c9cb0e5bd41b410b01bf498bf0f59997e041c 100644
--- a/cmd/version.go
+++ b/cmd/version.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 // Handles command-line version functionality
 
@@ -21,7 +21,7 @@ import (
 const currentVersion = "4.2.0"
 
 func Version() string {
-	out := fmt.Sprintf("Elixxir Cmix v%s -- %s\n\n", xxdk.SEMVER,
+	out := fmt.Sprintf("Elixxir Client v%s -- %s\n\n", xxdk.SEMVER,
 		xxdk.GITVERSION)
 	out += fmt.Sprintf("Dependencies:\n\n%s\n", xxdk.DEPENDENCIES)
 	return out
diff --git a/cmix/address/addressSpace.go b/cmix/address/addressSpace.go
index be6cd94abdfc1cabc9bc58ede4516dbe6a773f88..500797fa0a69ca58c10dc11973d539567fe092c8 100644
--- a/cmix/address/addressSpace.go
+++ b/cmix/address/addressSpace.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package address
 
 import (
diff --git a/cmix/address/addressSpace_test.go b/cmix/address/addressSpace_test.go
index 62b23793efe9dff74f5e6297d0d529d9da68bf29..aed3e9f9c950e1cc7da2039638745e639f72ee73 100644
--- a/cmix/address/addressSpace_test.go
+++ b/cmix/address/addressSpace_test.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package address
 
 import (
diff --git a/cmix/check.go b/cmix/check.go
index 899fe10db2a7420f493bf70e23d12065245ffd16..ed010a7625cafae25ed8bc7f87520529099b2ed1 100644
--- a/cmix/check.go
+++ b/cmix/check.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package cmix
 
 import (
diff --git a/cmix/check_test.go b/cmix/check_test.go
index 5ab2aaf943aac5645d224e07d2e7bca3620caf21..e828e4c1d64a981b5d878ff98b267c050f14829f 100644
--- a/cmix/check_test.go
+++ b/cmix/check_test.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package cmix
 
 import (
diff --git a/cmix/client.go b/cmix/client.go
index d164b4d2a60620176fe7fee12c5a26e95e351c99..71b2c3c206431c3c98eaac08098a36a444d30db0 100644
--- a/cmix/client.go
+++ b/cmix/client.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package cmix
 
@@ -188,14 +188,14 @@ func (c *client) initialize(ndf *ndf.NetworkDefinition) error {
 
 	// Set up critical message tracking (sendCmix only)
 	critSender := func(msg format.Message, recipient *id.ID, params CMIXParams,
-	) (id.Round, ephemeral.Id, error) {
+	) (rounds.Round, ephemeral.Id, error) {
 		compiler := func(round id.Round) (format.Message, error) {
 			return msg, nil
 		}
-		rid, eid, _, sendErr := sendCmixHelper(c.Sender, compiler, recipient, params, c.instance,
+		r, eid, _, sendErr := sendCmixHelper(c.Sender, compiler, recipient, params, c.instance,
 			c.session.GetCmixGroup(), c.Registrar, c.rng, c.events,
 			c.session.GetTransmissionID(), c.comms)
-		return rid, eid, sendErr
+		return r, eid, sendErr
 
 	}
 
@@ -251,6 +251,9 @@ func (c *client) Follow(report ClientErrorReport) (stoppable.Stoppable, error) {
 	// Start the processes for the identity handler
 	multi.Add(c.Tracker.StartProcesses())
 
+	//Start the critical processing thread
+	multi.Add(c.crit.startProcessies())
+
 	return multi, nil
 }
 
diff --git a/cmix/cmixMessageBuffer.go b/cmix/cmixMessageBuffer.go
index 54ba624ab9a203559de9bfcb6340adf1bddec8a6..0b4ac483889a938cee6335a888e3a122dd1fe4bb 100644
--- a/cmix/cmixMessageBuffer.go
+++ b/cmix/cmixMessageBuffer.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package cmix
 
@@ -52,7 +52,7 @@ func (cmh *cmixMessageHandler) SaveMessage(
 	}
 
 	// Save versioned object
-	return kv.Set(key, currentCmixMessageVersion, &obj)
+	return kv.Set(key, &obj)
 }
 
 // LoadMessage returns the message with the specified key from the key value
diff --git a/cmix/cmixMessageBuffer_test.go b/cmix/cmixMessageBuffer_test.go
index 1a9189a689726d2a4eec07a1d629d622e66b4d10..1318b3544c7fb393c23cac8593106649cccc111b 100644
--- a/cmix/cmixMessageBuffer_test.go
+++ b/cmix/cmixMessageBuffer_test.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package cmix
 
diff --git a/cmix/critical.go b/cmix/critical.go
index 03ebfc7b56429b0fd0e8f588fa5ca2fe2e809491..6e9dd64e5a30d95a0933818c9b79e763ec67fe05 100644
--- a/cmix/critical.go
+++ b/cmix/critical.go
@@ -1,6 +1,16 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package cmix
 
 import (
+	"gitlab.com/elixxir/client/cmix/rounds"
+	"time"
+
 	jww "github.com/spf13/jwalterweatherman"
 	"gitlab.com/elixxir/client/cmix/health"
 	"gitlab.com/elixxir/client/stoppable"
@@ -10,7 +20,6 @@ import (
 	"gitlab.com/elixxir/primitives/states"
 	"gitlab.com/xx_network/primitives/id"
 	"gitlab.com/xx_network/primitives/id/ephemeral"
-	"time"
 )
 
 const criticalRawMessagesKey = "RawCriticalMessages"
@@ -27,7 +36,7 @@ type roundEventRegistrar interface {
 // anonymous function to include the structures from client that critical is
 // not aware of.
 type criticalSender func(msg format.Message, recipient *id.ID,
-	params CMIXParams) (id.Round, ephemeral.Id, error)
+	params CMIXParams) (rounds.Round, ephemeral.Id, error)
 
 // critical is a structure that allows the auto resending of messages that must
 // be received.
@@ -58,6 +67,12 @@ func newCritical(kv *versioned.KV, hm health.Monitor,
 	return c
 }
 
+func (c *critical) startProcessies() *stoppable.Single {
+	stop := stoppable.NewSingle("criticalStopper")
+	go c.runCriticalMessages(stop)
+	return stop
+}
+
 func (c *critical) runCriticalMessages(stop *stoppable.Single) {
 	for {
 		select {
@@ -120,7 +135,7 @@ func (c *critical) evaluate(stop *stoppable.Single) {
 			round, _, err := c.send(msg, recipient, params)
 
 			// Pass to the handler
-			c.handle(msg, recipient, round, err)
+			c.handle(msg, recipient, round.ID, err)
 		}(msg, localRid, params)
 	}
 
diff --git a/cmix/critical_test.go b/cmix/critical_test.go
index 4126c57714955cbf446c4fab02c532eb0b159fd7..4b09fff7e44c281873b774833999514999c5e5f0 100644
--- a/cmix/critical_test.go
+++ b/cmix/critical_test.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package cmix
 
 import (
diff --git a/cmix/follow.go b/cmix/follow.go
index 29eb9035a252a00b3af8cc80a0768b54d8e528b1..4d8688369fc250805f4e35b47aa21179e9177ed6 100644
--- a/cmix/follow.go
+++ b/cmix/follow.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package cmix
 
@@ -26,6 +26,8 @@ import (
 	"bytes"
 	"encoding/binary"
 	"fmt"
+	"gitlab.com/elixxir/client/cmix/identity/receptionID"
+	"sync"
 	"sync/atomic"
 	"time"
 
@@ -68,7 +70,10 @@ func (c *client) followNetwork(report ClientErrorReport,
 	TrackTicker := time.NewTicker(debugTrackPeriod)
 	rng := c.rng.GetStream()
 
+	// abandon tracks rounds which data was not found out about in
+	// the verbose rounds debugging mode
 	abandon := func(round id.Round) { return }
+	dummyAbandon := func(round id.Round) { return }
 	if c.verboseRounds != nil {
 		abandon = func(round id.Round) {
 			c.verboseRounds.denote(round, Abandoned)
@@ -82,7 +87,50 @@ func (c *client) followNetwork(report ClientErrorReport,
 			stop.ToStopped()
 			return
 		case <-ticker.C:
-			c.follow(report, rng, c.comms, stop, abandon)
+
+			operator := func(toTrack []receptionID.IdentityUse) error {
+
+				// set up tracking tools
+				wg := &sync.WaitGroup{}
+				wg.Add(len(toTrack))
+
+				// trigger the first separately because it will get network state
+				// updates
+				go func() {
+					c.follow(toTrack[0], report, rng, c.comms, stop, abandon,
+						true)
+					wg.Done()
+				}()
+
+				//trigger all others without getting network state updates
+				for i := 1; i < len(toTrack); i++ {
+					go func(index int) {
+						c.follow(toTrack[index], report, rng, c.comms, stop,
+							dummyAbandon, false)
+						wg.Done()
+					}(i)
+				}
+
+				//wait for all to complete
+				wg.Wait()
+				return nil
+			}
+
+			// get the list of identities to track
+			stream := c.rng.GetStream()
+			err := c.Tracker.ForEach(
+				int(c.param.MaxParallelIdentityTracks),
+				stream,
+				c.Space.GetAddressSpaceWithoutWait(),
+				operator)
+			stream.Close()
+
+			if err != nil {
+				jww.ERROR.Printf("failed to operate on identities to "+
+					"track: %s", err)
+				continue
+			}
+
 		case <-TrackTicker.C:
 			numPolls := atomic.SwapUint64(c.tracker, 0)
 			if c.numLatencies != 0 {
@@ -108,18 +156,10 @@ func (c *client) followNetwork(report ClientErrorReport,
 	}
 }
 
-// follow executes each iteration of the follower.
-func (c *client) follow(report ClientErrorReport, rng csprng.Source,
-	comms followNetworkComms, stop *stoppable.Single,
-	abandon func(round id.Round)) {
-
-	// Get the identity we will poll for
-	identity, err := c.GetEphemeralIdentity(
-		rng, c.Space.GetAddressSpaceWithoutWait())
-	if err != nil {
-		jww.FATAL.Panicf(
-			"Failed to get an identity, this should be impossible: %+v", err)
-	}
+// follow executes an iteration of the follower for a specific identity
+func (c *client) follow(identity receptionID.IdentityUse,
+	report ClientErrorReport, rng csprng.Source, comms followNetworkComms,
+	stop *stoppable.Single, abandon func(round id.Round), getUpdates bool) {
 
 	// While polling with a fake identity, it is necessary to have populated
 	// earliestRound data. However, as with fake identities, we want the values
@@ -147,6 +187,7 @@ func (c *client) follow(report ClientErrorReport, rng csprng.Source,
 		ClientVersion:  []byte(version.String()),
 		FastPolling:    c.param.FastPolling,
 		LastRound:      uint64(identity.ER.Get()),
+		DisableUpdates: !getUpdates,
 	}
 
 	result, err := c.SendToAny(func(host *connect.Host) (interface{}, error) {
@@ -299,6 +340,7 @@ func (c *client) follow(report ClientErrorReport, rng csprng.Source,
 		if !hasMessage && c.verboseRounds != nil {
 			c.verboseRounds.denote(rid, RoundState(NoMessageAvailable))
 		}
+		//jww.INFO.Printf("[LOOKUP] round %d checked for %d, has message: %s", rid, identity.EphId.Int64(), hasMessage)
 		return hasMessage
 	}
 
@@ -349,10 +391,10 @@ func (c *client) follow(report ClientErrorReport, rng csprng.Source,
 		gwRoundsState.RangeUnchecked(
 			updatedEarliestRound, c.param.KnownRoundsThreshold, roundChecker)
 
-	jww.DEBUG.Printf("Processed RangeUnchecked, Oldest: %d, "+
+	jww.DEBUG.Printf("Processed RangeUnchecked for %d, Oldest: %d, "+
 		"firstUnchecked: %d, last Checked: %d, threshold: %d, "+
 		"NewEarliestRemaining: %d, NumWithMessages: %d, NumUnknown: %d",
-		updatedEarliestRound, gwRoundsState.GetFirstUnchecked(),
+		identity.EphId.Int64(), updatedEarliestRound, gwRoundsState.GetFirstUnchecked(),
 		gwRoundsState.GetLastChecked(), c.param.KnownRoundsThreshold,
 		earliestRemaining, len(roundsWithMessages), len(roundsUnknown))
 
diff --git a/cmix/follow_test.go b/cmix/follow_test.go
index ed81b15896d3d8c32b3aca6714550af48b7537f7..7b887cc1e874f49c2ae0226cfa28a4736956e689 100644
--- a/cmix/follow_test.go
+++ b/cmix/follow_test.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package cmix
 
 //func TestClient_Follow(t *testing.T) {
diff --git a/cmix/gateway/hostPool.go b/cmix/gateway/hostPool.go
index c90a825fafa8b9b4a9fee9988fe5ab94d1b347dc..c37dbdf2fdcda4b8f9f8fac7f9339640809e40fe 100644
--- a/cmix/gateway/hostPool.go
+++ b/cmix/gateway/hostPool.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 // Package gateway Handles functionality related to providing Gateway
 // connect.Host objects for message sending to the rest of the client
@@ -247,7 +247,7 @@ func newHostPool(poolParams PoolParams, rng *fastRNG.StreamGenerator,
 		}
 	} else {
 		jww.WARN.Printf(
-			"Building new HostPool because no HostList stored: %+v", err)
+			"Building new HostPool because no HostList stored: %s", err.Error())
 	}
 
 	// Build the initial HostPool and return
diff --git a/cmix/gateway/hostpool_test.go b/cmix/gateway/hostpool_test.go
index f5a49cc4e9c0d052ac704d901976da4635069c3c..8f35e91f41d508806469a5f4f274f61d1a0c2adf 100644
--- a/cmix/gateway/hostpool_test.go
+++ b/cmix/gateway/hostpool_test.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package gateway
 
diff --git a/cmix/gateway/sender.go b/cmix/gateway/sender.go
index 1ccff1fb8b0c18550cfad2dd7db48d04aaae89d0..98dffa6a2de35328d4b42f27d920144663de4095 100644
--- a/cmix/gateway/sender.go
+++ b/cmix/gateway/sender.go
@@ -1,7 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2021 Privategrity Corporation                                   /
-//                                                                             /
-// All rights reserved.                                                        /
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 // Contains gateway message sending wrappers
diff --git a/cmix/gateway/sender_test.go b/cmix/gateway/sender_test.go
index b6de48005f188dadc6e1f4053d80f84c53af291d..b891940d13983a8dc314757c11ecc6580d520e63 100644
--- a/cmix/gateway/sender_test.go
+++ b/cmix/gateway/sender_test.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package gateway
 
diff --git a/cmix/gateway/storeHostList.go b/cmix/gateway/storeHostList.go
index d71d17b53e235ad5eb02860d8951794304ed59cc..d227111f7319a67963bbc14d511f25d6b228b025 100644
--- a/cmix/gateway/storeHostList.go
+++ b/cmix/gateway/storeHostList.go
@@ -1,8 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package gateway
@@ -36,7 +36,7 @@ func saveHostList(kv *versioned.KV, list []*id.ID) error {
 		Timestamp: netTime.Now(),
 	}
 
-	return kv.Set(hostListKey, hostListVersion, obj)
+	return kv.Set(hostListKey, obj)
 }
 
 // getHostList returns the host list from storage.
diff --git a/cmix/gateway/storeHostList_test.go b/cmix/gateway/storeHostList_test.go
index 6dddef1f25f0737cda09b8b53802d4431806bd0b..54757ab5cbeaac6a680274729b32529e7e6c3f7a 100644
--- a/cmix/gateway/storeHostList_test.go
+++ b/cmix/gateway/storeHostList_test.go
@@ -1,8 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package gateway
diff --git a/cmix/gateway/utils_test.go b/cmix/gateway/utils_test.go
index d9dc77cf5674127e3e30a3ecd0896dcdba16816f..7846da5d89547e66ccd8996e24c3d3fe4bb0c7e0 100644
--- a/cmix/gateway/utils_test.go
+++ b/cmix/gateway/utils_test.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package gateway
 
diff --git a/cmix/health/tracker.go b/cmix/health/tracker.go
index 3f2a932e9a1b82efdeff5f8ca2bcd1c1c5e3f8fd..537ec320cae8341b341653e4af07c93fc37c50ce 100644
--- a/cmix/health/tracker.go
+++ b/cmix/health/tracker.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 // Contains functionality related to the event model driven network health
 // tracker.
diff --git a/cmix/health/tracker_test.go b/cmix/health/tracker_test.go
index 1c2a44aa71d4cc6a4ae30d15575c83113601edcf..1f74c7b4688037e90f9c9cf5d0147e1990a7e35a 100644
--- a/cmix/health/tracker_test.go
+++ b/cmix/health/tracker_test.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package health
 
diff --git a/cmix/identity/receptionID/IdentityUse.go b/cmix/identity/receptionID/IdentityUse.go
index 7255a65faafb0d73a4d4d7f44e80e92173d34894..de9ade02301a5a9a84c7363e3582b4228a70ae62 100644
--- a/cmix/identity/receptionID/IdentityUse.go
+++ b/cmix/identity/receptionID/IdentityUse.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package receptionID
 
 import (
diff --git a/cmix/identity/receptionID/fake.go b/cmix/identity/receptionID/fake.go
index 5462690d531fdeeee1b0c2a9e7d60981af8f95aa..45dd72e5f29e80709a7acd41e9cadfd2d78a4ae4 100644
--- a/cmix/identity/receptionID/fake.go
+++ b/cmix/identity/receptionID/fake.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package receptionID
 
 import (
diff --git a/cmix/identity/receptionID/fake_test.go b/cmix/identity/receptionID/fake_test.go
index 27134207200732d3cdecb943f29a1ecb259a3b42..14940f7f60c8e057273f2f2559e346505fe89690 100644
--- a/cmix/identity/receptionID/fake_test.go
+++ b/cmix/identity/receptionID/fake_test.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package receptionID
 
 import (
diff --git a/cmix/identity/receptionID/identity.go b/cmix/identity/receptionID/identity.go
index 96767b8a7a7dfa8813e2b50298f00c04b98beb66..bba7823789480636710b520d79d4deeadbfa1dbd 100644
--- a/cmix/identity/receptionID/identity.go
+++ b/cmix/identity/receptionID/identity.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package receptionID
 
 import (
@@ -73,7 +80,7 @@ func (i Identity) store(kv *versioned.KV) error {
 	}
 
 	// Store the data
-	err = kv.Set(identityStorageKey, identityStorageVersion, obj)
+	err = kv.Set(identityStorageKey, obj)
 	if err != nil {
 		return errors.WithMessage(err, "Failed to store Identity")
 	}
diff --git a/cmix/identity/receptionID/identity_test.go b/cmix/identity/receptionID/identity_test.go
index d1f26598684daad8550cf5476ba04b163023f956..c893a7dbd87fd3d559801f8be7007cf4535fcc6a 100644
--- a/cmix/identity/receptionID/identity_test.go
+++ b/cmix/identity/receptionID/identity_test.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package receptionID
 
 import (
diff --git a/cmix/identity/receptionID/registration.go b/cmix/identity/receptionID/registration.go
index 2655eee3a864558365e1cf2e1d8c6ea81ce2c4a0..9f25f54097a72448825e44452f3411f829237844 100644
--- a/cmix/identity/receptionID/registration.go
+++ b/cmix/identity/receptionID/registration.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package receptionID
 
 import (
diff --git a/cmix/identity/receptionID/registration_test.go b/cmix/identity/receptionID/registration_test.go
index cd8d608ac725c1750c99b723c3528f46719020fe..7206df57b4788dee47712662e4d373e33591df0f 100644
--- a/cmix/identity/receptionID/registration_test.go
+++ b/cmix/identity/receptionID/registration_test.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package receptionID
 
 import (
diff --git a/cmix/identity/receptionID/store.go b/cmix/identity/receptionID/store.go
index e13eddfac252e4fd9daf2032f920f0e110a75dfe..967c22e034270d726b2c4e216d460dc767e0dbd2 100644
--- a/cmix/identity/receptionID/store.go
+++ b/cmix/identity/receptionID/store.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package receptionID
 
 import (
@@ -6,6 +13,7 @@ import (
 	jww "github.com/spf13/jwalterweatherman"
 	"gitlab.com/elixxir/client/storage/versioned"
 	"gitlab.com/xx_network/crypto/large"
+	"gitlab.com/xx_network/crypto/shuffle"
 	"gitlab.com/xx_network/primitives/id"
 	"gitlab.com/xx_network/primitives/id/ephemeral"
 	"gitlab.com/xx_network/primitives/netTime"
@@ -21,6 +29,8 @@ const (
 	receptionStoreStorageVersion = 0
 )
 
+var InvalidRequestedNumIdentities = errors.New("cannot get less than one identity(s)")
+
 type Store struct {
 	// Identities which are being actively checked
 	active  []*registration
@@ -54,7 +64,7 @@ func NewOrLoadStore(kv *versioned.KV) *Store {
 	s, err := loadStore(kv)
 	if err != nil {
 		jww.WARN.Printf(
-			"ReceptionID store not found, creating a new one: %+v", err)
+			"ReceptionID store not found, creating a new one: %s", err.Error())
 
 		s = &Store{
 			active:  []*registration{},
@@ -122,7 +132,7 @@ func (s *Store) save() error {
 		Data:      data,
 	}
 
-	err = s.kv.Set(receptionStoreStorageKey, receptionStoreStorageVersion, obj)
+	err = s.kv.Set(receptionStoreStorageKey, obj)
 	if err != nil {
 		return errors.WithMessage(err, "Failed to store reception store")
 	}
@@ -150,7 +160,15 @@ func (s *Store) makeStoredReferences() []storedReference {
 	return identities[:i]
 }
 
-func (s *Store) GetIdentity(rng io.Reader, addressSize uint8) (IdentityUse, error) {
+// ForEach operates on 'n' identities randomly in a random order.
+// if no identities exist, it will operate on a single fake identity
+func (s *Store) ForEach(n int, rng io.Reader,
+	addressSize uint8, operate func([]IdentityUse) error) error {
+
+	if n < 1 {
+		return InvalidRequestedNumIdentities
+	}
+
 	s.mux.Lock()
 	defer s.mux.Unlock()
 
@@ -159,26 +177,29 @@ func (s *Store) GetIdentity(rng io.Reader, addressSize uint8) (IdentityUse, erro
 	// Remove any now expired identities
 	s.prune(now)
 
-	var identity IdentityUse
-	var err error
+	var identities []IdentityUse
 
 	// If the list is empty, then return a randomly generated identity to poll
 	// with so that we can continue tracking the network and to further
 	// obfuscate network identities.
 	if len(s.active) == 0 {
-		identity, err = generateFakeIdentity(rng, addressSize, now)
+		fakeIdentity, err := generateFakeIdentity(rng, addressSize, now)
 		if err != nil {
 			jww.FATAL.Panicf(
 				"Failed to generate a new ID when none available: %+v", err)
 		}
+		identities = append(identities, fakeIdentity)
+		// otherwise, select identities to return using a fisher-yates
 	} else {
-		identity, err = s.selectIdentity(rng, now)
+		var err error
+		identities, err = s.selectIdentities(n, rng, now)
 		if err != nil {
-			jww.FATAL.Panicf("Failed to select an ID: %+v", err)
+			jww.FATAL.Panicf("Failed to select a list of IDs: %+v", err)
 		}
 	}
 
-	return identity, nil
+	// do the passed operation on all identities
+	return operate(identities)
 }
 
 func (s *Store) AddIdentity(identity Identity) error {
@@ -221,10 +242,11 @@ func (s *Store) RemoveIdentity(ephID ephemeral.Id) {
 	s.mux.Lock()
 	defer s.mux.Unlock()
 
-	for i, inQuestion := range s.active {
+	for i := 0; i < len(s.active); i++ {
+		inQuestion := s.active[i]
 		if inQuestion.EphId == ephID {
 			s.active = append(s.active[:i], s.active[i+1:]...)
-
+			delete(s.present, makeIdHash(inQuestion.EphId, inQuestion.Source))
 			err := inQuestion.Delete()
 			if err != nil {
 				jww.FATAL.Panicf("Failed to delete identity: %+v", err)
@@ -237,6 +259,8 @@ func (s *Store) RemoveIdentity(ephID ephemeral.Id) {
 				}
 			}
 
+			i--
+
 			return
 		}
 	}
@@ -247,16 +271,20 @@ func (s *Store) RemoveIdentities(source *id.ID) {
 	defer s.mux.Unlock()
 
 	doSave := false
-	for i, inQuestion := range s.active {
+	for i := 0; i < len(s.active); i++ {
+		inQuestion := s.active[i]
 		if inQuestion.Source.Cmp(source) {
 			s.active = append(s.active[:i], s.active[i+1:]...)
-
+			delete(s.present, makeIdHash(inQuestion.EphId, inQuestion.Source))
+			jww.INFO.Printf("Removing Identity %s:%d from tracker",
+				inQuestion.Source, inQuestion.EphId.Int64())
 			err := inQuestion.Delete()
 			if err != nil {
 				jww.FATAL.Panicf("Failed to delete identity: %+v", err)
 			}
 
 			doSave = doSave || !inQuestion.Ephemeral
+			i--
 		}
 	}
 	if doSave {
@@ -298,6 +326,7 @@ func (s *Store) prune(now time.Time) {
 			pruned = append(pruned, inQuestion.EphId.Int64())
 
 			s.active = append(s.active[:i], s.active[i+1:]...)
+			delete(s.present, makeIdHash(inQuestion.EphId, inQuestion.Source))
 
 			i--
 		}
@@ -313,6 +342,8 @@ func (s *Store) prune(now time.Time) {
 	}
 }
 
+// selectIdentity returns a random identity in an IdentityUse object and
+// increments its usage if necessary
 func (s *Store) selectIdentity(rng io.Reader, now time.Time) (IdentityUse, error) {
 	// Choose a member from the list
 	var selected *registration
@@ -320,7 +351,7 @@ func (s *Store) selectIdentity(rng io.Reader, now time.Time) (IdentityUse, error
 	if len(s.active) == 1 {
 		selected = s.active[0]
 	} else {
-		seed := make([]byte, 32)
+		seed := make([]byte, 32) //use 256 bits of entropy for the seed
 		if _, err := rng.Read(seed); err != nil {
 			return IdentityUse{}, errors.WithMessage(err, "Failed to choose "+
 				"ID due to RNG failure")
@@ -334,10 +365,6 @@ func (s *Store) selectIdentity(rng io.Reader, now time.Time) (IdentityUse, error
 		selected = s.active[selectedNum.Uint64()]
 	}
 
-	if now.After(selected.End) {
-		selected.ExtraChecks--
-	}
-
 	jww.TRACE.Printf("Selected identity: EphId: %d  ID: %s  End: %s  "+
 		"StartValid: %s  EndValid: %s",
 		selected.EphId.Int64(), selected.Source,
@@ -345,11 +372,64 @@ func (s *Store) selectIdentity(rng io.Reader, now time.Time) (IdentityUse, error
 		selected.StartValid.Format("01/02/06 03:04:05 pm"),
 		selected.EndValid.Format("01/02/06 03:04:05 pm"))
 
+	return useIdentity(selected, now), nil
+}
+
+// selectIdentities returns up to 'n' identities in an IdentityUse object
+// selected via fisher-yates and increments their usage if necessary
+func (s *Store) selectIdentities(n int, rng io.Reader, now time.Time) ([]IdentityUse, error) {
+	// Choose a member from the list
+	selected := make([]IdentityUse, 0, n)
+
+	if len(s.active) == 1 {
+		selected = append(selected, useIdentity(s.active[0], now))
+	} else {
+
+		// make the seed
+		seed := make([]byte, 32) //use 256 bits of entropy for the seed
+		if _, err := rng.Read(seed); err != nil {
+			return nil, errors.WithMessage(err, "Failed to choose "+
+				"ID due to RNG failure")
+		}
+
+		// make the list to shuffle
+		registered := make([]*registration, 0, len(s.active))
+		for i := 0; i < len(s.active); i++ {
+			registered = append(registered, s.active[i])
+		}
+
+		//shuffle the list via fisher-yates
+		registeredProxy := shuffle.SeededShuffle(len(s.active), seed)
+
+		//convert the list to identity use
+		for i := 0; i < len(registered) && (i < n); i++ {
+			selected = append(selected,
+				useIdentity(registered[registeredProxy[i]], now))
+		}
+
+	}
+
+	jww.TRACE.Printf("Selected %d identities, first identity: EphId: %d  ID: %s  End: %s  "+
+		"StartValid: %s  EndValid: %s", len(selected),
+		selected[0].EphId.Int64(), selected[0].Source,
+		selected[0].End.Format("01/02/06 03:04:05 pm"),
+		selected[0].StartValid.Format("01/02/06 03:04:05 pm"),
+		selected[0].EndValid.Format("01/02/06 03:04:05 pm"))
+
+	return selected, nil
+}
+
+// useIdentity makes the public IdentityUse object from a private *registration
+// and deals with denoting the usage in the *registration if nessessay
+func useIdentity(selected *registration, now time.Time) IdentityUse {
+	if now.After(selected.End) {
+		selected.ExtraChecks--
+	}
 	return IdentityUse{
 		Identity: selected.Identity,
 		Fake:     false,
 		UR:       selected.UR,
 		ER:       selected.ER,
 		CR:       selected.CR,
-	}, nil
+	}
 }
diff --git a/cmix/identity/receptionID/store/checkedRounds.go b/cmix/identity/receptionID/store/checkedRounds.go
index 3ef3a61c07c131c5671fc0729e22df9f85715b49..b117f0e06a58664094f78a3bee3325c3a30f5239 100644
--- a/cmix/identity/receptionID/store/checkedRounds.go
+++ b/cmix/identity/receptionID/store/checkedRounds.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package store
 
 import (
diff --git a/cmix/identity/receptionID/store/checkedRounds_test.go b/cmix/identity/receptionID/store/checkedRounds_test.go
index 5ddc5984d10dab0502982d0a1c98761bc13801ce..1f9f623785c13167167b81655023152eb02b0870 100644
--- a/cmix/identity/receptionID/store/checkedRounds_test.go
+++ b/cmix/identity/receptionID/store/checkedRounds_test.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package store
 
 import (
diff --git a/cmix/identity/receptionID/store/earliestRound.go b/cmix/identity/receptionID/store/earliestRound.go
index fe1b60abd17932382d92f1df6d03ca480727d817..3d2ea3272b88bfe1764501897eb810c302f62ae5 100644
--- a/cmix/identity/receptionID/store/earliestRound.go
+++ b/cmix/identity/receptionID/store/earliestRound.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package store
 
 import (
@@ -65,8 +72,7 @@ func (ur *EarliestRound) save() {
 			Data:      urStr,
 		}
 
-		err = ur.kv.Set(earliestRoundStorageKey,
-			earliestRoundStorageVersion, obj)
+		err = ur.kv.Set(earliestRoundStorageKey, obj)
 		if err != nil {
 			jww.FATAL.Panicf("Failed to store the earliest round: %+v", err)
 		}
diff --git a/cmix/identity/receptionID/store/unknownRounds.go b/cmix/identity/receptionID/store/unknownRounds.go
index b14c939abdd27e72a284bf37ba71e763b6bd0536..da9fead7e48c774c7a866626a2000e13e90a2aab 100644
--- a/cmix/identity/receptionID/store/unknownRounds.go
+++ b/cmix/identity/receptionID/store/unknownRounds.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package store
 
@@ -223,7 +223,7 @@ func (urs *UnknownRounds) save() error {
 	}
 
 	// Save to disk
-	return urs.kv.Set(unknownRoundsStorageKey, unknownRoundsStorageVersion, obj)
+	return urs.kv.Set(unknownRoundsStorageKey, obj)
 }
 
 func (urs *UnknownRounds) Delete() {
diff --git a/cmix/identity/receptionID/store/unknownRounds_test.go b/cmix/identity/receptionID/store/unknownRounds_test.go
index f8beea3a7adbdd8c6fc52514ffb6950280014982..ac0c85da6efdf74c847f87676c29eb645951487c 100644
--- a/cmix/identity/receptionID/store/unknownRounds_test.go
+++ b/cmix/identity/receptionID/store/unknownRounds_test.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package store
 
diff --git a/cmix/identity/receptionID/store_test.go b/cmix/identity/receptionID/store_test.go
index 19a53f97b11a9e7abaef0ecf3c2c0c1698602105..5161469cfd7c044eddade131e8f76b90c6c30678 100644
--- a/cmix/identity/receptionID/store_test.go
+++ b/cmix/identity/receptionID/store_test.go
@@ -1,11 +1,21 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package receptionID
 
 import (
 	"bytes"
+	"encoding/binary"
 	"encoding/json"
 	"gitlab.com/elixxir/client/storage/versioned"
+	"gitlab.com/elixxir/crypto/hash"
 	"gitlab.com/elixxir/ekv"
 	"gitlab.com/xx_network/primitives/netTime"
+	"math"
 	"math/rand"
 	"reflect"
 	"testing"
@@ -141,27 +151,226 @@ func TestStore_makeStoredReferences(t *testing.T) {
 	}
 }
 
-func TestStore_GetIdentity(t *testing.T) {
+func TestStore_GetIdentities(t *testing.T) {
 	kv := versioned.NewKV(ekv.MakeMemstore())
 	s := NewOrLoadStore(kv)
 	prng := rand.New(rand.NewSource(42))
-	testID, err := generateFakeIdentity(prng, 15, netTime.Now())
+
+	numToTest := 100
+
+	idsGenerated := make(map[uint64]interface{})
+
+	for i := 0; i < numToTest; i++ {
+		testID, err := generateFakeIdentity(prng, 15, netTime.Now())
+		if err != nil {
+			t.Fatalf("Failed to generate fake ID: %+v", err)
+		}
+		testID.Fake = false
+		if s.AddIdentity(testID.Identity) != nil {
+			t.Errorf("AddIdentity() produced an error: %+v", err)
+		}
+
+		idsGenerated[getIDFp(testID.EphemeralIdentity)] = nil
+
+	}
+
+	//get one
+	var idu []IdentityUse
+	o := func(a []IdentityUse) error {
+		idu = a
+		return nil
+	}
+	err := s.ForEach(1, prng, 15, o)
 	if err != nil {
-		t.Fatalf("Failed to generate fake ID: %+v", err)
+		t.Errorf("GetIdentity() produced an error: %+v", err)
 	}
-	if s.AddIdentity(testID.Identity) != nil {
-		t.Errorf("AddIdentity() produced an error: %+v", err)
+
+	if _, exists := idsGenerated[getIDFp(idu[0].EphemeralIdentity)]; !exists ||
+		idu[0].Fake {
+		t.Errorf("An unknown or fake identity was returned")
+	}
+
+	//get three
+	err = s.ForEach(3, prng, 15, o)
+	if err != nil {
+		t.Errorf("GetIdentity() produced an error: %+v", err)
+	}
+
+	if len(idu) != 3 {
+		t.Errorf("the wrong number of identities was returned")
+	}
+
+	for i := 0; i < len(idu); i++ {
+		if _, exists := idsGenerated[getIDFp(idu[i].EphemeralIdentity)]; !exists ||
+			idu[i].Fake {
+			t.Errorf("An unknown or fake identity was returned")
+		}
+	}
+
+	//get ten
+	err = s.ForEach(10, prng, 15, o)
+	if err != nil {
+		t.Errorf("GetIdentity() produced an error: %+v", err)
+	}
+
+	if len(idu) != 10 {
+		t.Errorf("the wrong number of identities was returned")
+	}
+
+	for i := 0; i < len(idu); i++ {
+		if _, exists := idsGenerated[getIDFp(idu[i].EphemeralIdentity)]; !exists ||
+			idu[i].Fake {
+			t.Errorf("An unknown or fake identity was returned")
+		}
+	}
+
+	//get fifty
+	err = s.ForEach(50, prng, 15, o)
+	if err != nil {
+		t.Errorf("GetIdentity() produced an error: %+v", err)
+	}
+
+	if len(idu) != 50 {
+		t.Errorf("the wrong number of identities was returned")
+	}
+
+	for i := 0; i < len(idu); i++ {
+		if _, exists := idsGenerated[getIDFp(idu[i].EphemeralIdentity)]; !exists ||
+			idu[i].Fake {
+			t.Errorf("An unknown or fake identity was returned")
+		}
+	}
+
+	//get 100
+	err = s.ForEach(100, prng, 15, o)
+	if err != nil {
+		t.Errorf("GetIdentity() produced an error: %+v", err)
+	}
+
+	if len(idu) != 100 {
+		t.Errorf("the wrong number of identities was returned")
+	}
+
+	for i := 0; i < len(idu); i++ {
+		if _, exists := idsGenerated[getIDFp(idu[i].EphemeralIdentity)]; !exists ||
+			idu[i].Fake {
+			t.Errorf("An unknown or fake identity was returned")
+		}
+	}
+
+	//get 1000, should only return 100
+	err = s.ForEach(1000, prng, 15, o)
+	if err != nil {
+		t.Errorf("GetIdentity() produced an error: %+v", err)
+	}
+
+	if len(idu) != 100 {
+		t.Errorf("the wrong number of identities was returned")
+	}
+
+	for i := 0; i < len(idu); i++ {
+		if _, exists := idsGenerated[getIDFp(idu[i].EphemeralIdentity)]; !exists ||
+			idu[i].Fake {
+			t.Errorf("An unknown or fake identity was returned")
+		}
 	}
 
-	idu, err := s.GetIdentity(prng, 15)
+	// get 100 a second time and make sure the order is not the same as a
+	// smoke test that the shuffle is working
+	var idu2 []IdentityUse
+	o2 := func(a []IdentityUse) error {
+		idu2 = a
+		return nil
+	}
+
+	err = s.ForEach(1000, prng, 15, o2)
 	if err != nil {
 		t.Errorf("GetIdentity() produced an error: %+v", err)
 	}
 
-	if !testID.Equal(idu.Identity) {
-		t.Errorf("GetIdentity() did not return the expected Identity."+
-			"\nexpected: %s\nreceived: %s", testID, idu)
+	diferent := false
+	for i := 0; i < len(idu); i++ {
+		if !idu[i].Source.Cmp(idu2[i].Source) {
+			diferent = true
+			break
+		}
+	}
+
+	if !diferent {
+		t.Errorf("The 2 100 shuffels retruned the same result, shuffling" +
+			" is likley not occuring")
+	}
+
+}
+
+func TestStore_GetIdentities_NoIdentities(t *testing.T) {
+	kv := versioned.NewKV(ekv.MakeMemstore())
+	s := NewOrLoadStore(kv)
+	prng := rand.New(rand.NewSource(42))
+
+	var idu []IdentityUse
+	o := func(a []IdentityUse) error {
+		idu = a
+		return nil
+	}
+
+	err := s.ForEach(5, prng, 15, o)
+	if err != nil {
+		t.Errorf("GetIdentities() produced an error: %+v", err)
+	}
+
+	if len(idu) != 1 {
+		t.Errorf("GetIdenties() did not return only one identity " +
+			"when looking for a fake")
+	}
+
+	if !idu[0].Fake {
+		t.Errorf("GetIdenties() did not return a fake identity " +
+			"when only one is avalible")
+	}
+}
+
+func TestStore_GetIdentities_BadNum(t *testing.T) {
+	kv := versioned.NewKV(ekv.MakeMemstore())
+	s := NewOrLoadStore(kv)
+	prng := rand.New(rand.NewSource(42))
+
+	o := func(a []IdentityUse) error {
+		return nil
+	}
+
+	err := s.ForEach(0, prng, 15, o)
+	if err == nil {
+		t.Errorf("GetIdentities() shoud error with bad num value")
+	}
+
+	err = s.ForEach(-1, prng, 15, o)
+	if err == nil {
+		t.Errorf("GetIdentities() shoud error with bad num value")
+	}
+
+	err = s.ForEach(-100, prng, 15, o)
+	if err == nil {
+		t.Errorf("GetIdentities() shoud error with bad num value")
 	}
+
+	err = s.ForEach(-1000000, prng, 15, o)
+	if err == nil {
+		t.Errorf("GetIdentities() shoud error with bad num value")
+	}
+
+	err = s.ForEach(math.MinInt64, prng, 15, o)
+	if err == nil {
+		t.Errorf("GetIdentities() shoud error with bad num value")
+	}
+}
+
+func getIDFp(identity EphemeralIdentity) uint64 {
+	h, _ := hash.NewCMixHash()
+	h.Write(identity.EphId[:])
+	h.Write(identity.Source.Bytes())
+	r := h.Sum(nil)
+	return binary.BigEndian.Uint64(r)
 }
 
 func TestStore_AddIdentity(t *testing.T) {
diff --git a/cmix/identity/tracker.go b/cmix/identity/tracker.go
index 961aac77627f0f5ef15ed35b839c2c5eaafa9b4b..7ab08da034fbdd1dbbbfd35ff54b7fc72c273929 100644
--- a/cmix/identity/tracker.go
+++ b/cmix/identity/tracker.go
@@ -1,16 +1,15 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package identity
 
 import (
 	"encoding/json"
 	"io"
-	"io/fs"
 	"sync"
 	"time"
 
@@ -50,12 +49,13 @@ type Tracker interface {
 	StartProcesses() stoppable.Stoppable
 	AddIdentity(id *id.ID, validUntil time.Time, persistent bool)
 	RemoveIdentity(id *id.ID)
-	GetEphemeralIdentity(rng io.Reader, addressSize uint8) (receptionID.IdentityUse, error)
+	ForEach(n int, rng io.Reader, addressSize uint8,
+		operator func([]receptionID.IdentityUse) error) error
 	GetIdentity(get *id.ID) (TrackedID, error)
 }
 
 type manager struct {
-	tracked        []TrackedID
+	tracked        []*TrackedID
 	ephemeral      *receptionID.Store
 	session        storage.Session
 	newIdentity    chan TrackedID
@@ -76,7 +76,7 @@ type TrackedID struct {
 func NewOrLoadTracker(session storage.Session, addrSpace address.Space) *manager {
 	// Initialization
 	t := &manager{
-		tracked:        make([]TrackedID, 0),
+		tracked:        make([]*TrackedID, 0),
 		session:        session,
 		newIdentity:    make(chan TrackedID, trackedIDChanSize),
 		deleteIdentity: make(chan *id.ID, deleteIDChanSize),
@@ -86,13 +86,13 @@ func NewOrLoadTracker(session storage.Session, addrSpace address.Space) *manager
 
 	// Load this structure
 	err := t.load()
-	if err != nil && errors.Is(err, fs.ErrNotExist) {
+	if err != nil && !t.session.GetKV().Exists(err) {
 		oldTimestamp, err2 := getOldTimestampStore(t.session)
 		if err2 == nil {
 			jww.WARN.Printf("No tracked identities found, creating a new " +
 				"tracked identity from legacy stored timestamp.")
 
-			t.tracked = append(t.tracked, TrackedID{
+			t.tracked = append(t.tracked, &TrackedID{
 				// Make the next generation now so a generation triggers on
 				// first run
 				NextGeneration: netTime.Now(),
@@ -143,10 +143,14 @@ func (t *manager) RemoveIdentity(id *id.ID) {
 	t.deleteIdentity <- id
 }
 
-// GetEphemeralIdentity returns an ephemeral Identity to poll the network with.
-func (t *manager) GetEphemeralIdentity(rng io.Reader, addressSize uint8) (
-	receptionID.IdentityUse, error) {
-	return t.ephemeral.GetIdentity(rng, addressSize)
+// ForEach passes a fisher-yates shuffled list of up to 'num'
+// ephemeral identities into the operation function. It will pass a
+// fake identity if none are available
+// and less than 'num' if less than 'num' are available.
+// 'num' must be positive non-zero
+func (t *manager) ForEach(n int, rng io.Reader, addressSize uint8,
+	operator func([]receptionID.IdentityUse) error) error {
+	return t.ephemeral.ForEach(n, rng, addressSize, operator)
 }
 
 // GetIdentity returns a currently tracked identity
@@ -155,7 +159,7 @@ func (t *manager) GetIdentity(get *id.ID) (TrackedID, error) {
 	defer t.mux.Unlock()
 	for i := range t.tracked {
 		if get.Cmp(t.tracked[i].Source) {
-			return t.tracked[i], nil
+			return *t.tracked[i], nil
 		}
 	}
 	return TrackedID{}, errors.Errorf("could not find id %s", get)
@@ -201,16 +205,18 @@ func (t *manager) track(stop *stoppable.Single) {
 			if !isOld {
 				jww.DEBUG.Printf("Tracking new identity %s", newIdentity.Source)
 				// Otherwise, add it to the list and run
-				t.tracked = append(t.tracked, newIdentity)
+				t.tracked = append(t.tracked, &newIdentity)
 			}
 
 			t.save()
 			continue
 
 		case deleteID := <-t.deleteIdentity:
+			removed := false
 			for i := range t.tracked {
 				inQuestion := t.tracked[i]
 				if inQuestion.Source.Cmp(deleteID) {
+					removed = true
 					t.tracked = append(t.tracked[:i], t.tracked[i+1:]...)
 					t.save()
 					// Requires manual deletion in case identity is deleted before expiration
@@ -218,6 +224,9 @@ func (t *manager) track(stop *stoppable.Single) {
 					break
 				}
 			}
+			if !removed {
+				jww.WARN.Printf("Identity %s failed to be removed from tracker", deleteID)
+			}
 		case <-stop.Quit():
 			t.addrSpace.UnregisterAddressSpaceNotification(addressSpaceSizeChanTag)
 			stop.ToStopped()
@@ -236,7 +245,8 @@ func (t *manager) processIdentities(addressSize uint8) time.Time {
 	nextEvent := netTime.Now().Add(time.Duration(ephemeral.Period))
 
 	// Loop through every tracked ID and see if any operations are needed
-	for i, inQuestion := range t.tracked {
+	for i := range t.tracked {
+		inQuestion := t.tracked[i]
 		// Generate new ephemeral if is time for it
 		if netTime.Now().After(inQuestion.NextGeneration) {
 			nextGeneration := t.generateIdentitiesOverRange(inQuestion, addressSize)
@@ -267,7 +277,7 @@ func (t *manager) processIdentities(addressSize uint8) time.Time {
 
 	// Process any deletions
 	if len(toRemove) > 0 {
-		newTracked := make([]TrackedID, 0, len(t.tracked))
+		newTracked := make([]*TrackedID, 0, len(t.tracked))
 		for i := range t.tracked {
 			if _, remove := toRemove[i]; !remove {
 				newTracked = append(newTracked, t.tracked[i])
@@ -305,7 +315,7 @@ func unmarshalTimestamp(lastTimestampObj *versioned.Object) (time.Time, error) {
 
 // generateIdentitiesOverRange generates and adds all not yet existing ephemeral Ids
 // and returns the timestamp of the next generation for the given TrackedID
-func (t *manager) generateIdentitiesOverRange(inQuestion TrackedID,
+func (t *manager) generateIdentitiesOverRange(inQuestion *TrackedID,
 	addressSize uint8) time.Time {
 	// Ensure that ephemeral IDs will not be generated after the
 	// identity is invalid
@@ -374,7 +384,7 @@ func (t *manager) save() {
 
 	for i := range t.tracked {
 		if t.tracked[i].Persistent {
-			persistent = append(persistent, t.tracked[i])
+			persistent = append(persistent, *t.tracked[i])
 		}
 	}
 
@@ -393,7 +403,7 @@ func (t *manager) save() {
 		Data:      data,
 	}
 
-	err = t.session.GetKV().Set(TrackerListKey, TrackerListVersion, obj)
+	err = t.session.GetKV().Set(TrackerListKey, obj)
 	if err != nil {
 		jww.FATAL.Panicf("Unable to save TrackedID list: %+v", err)
 	}
diff --git a/cmix/identity/tracker_test.go b/cmix/identity/tracker_test.go
index d16f64b5526f30e2d9719974ad1f82560b7f6b1f..d1d75b078e5d21c326d1658247177aa10a2d4d2d 100644
--- a/cmix/identity/tracker_test.go
+++ b/cmix/identity/tracker_test.go
@@ -1,7 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2022 Privategrity Corporation                                   /
-//                                                                             /
-// All rights reserved.                                                        /
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package identity
@@ -67,7 +68,7 @@ func TestManager_processIdentities(t *testing.T) {
 	addrSpace.UpdateAddressSpace(18)
 	session := storage.InitTestingSession(t)
 	m := &manager{
-		tracked:        make([]TrackedID, 0),
+		tracked:        make([]*TrackedID, 0),
 		session:        session,
 		newIdentity:    make(chan TrackedID, trackedIDChanSize),
 		deleteIdentity: make(chan *id.ID, deleteIDChanSize),
@@ -79,7 +80,7 @@ func TestManager_processIdentities(t *testing.T) {
 	// Add some expired test IDs
 	testId := id.NewIdFromUInt(0, id.User, t)
 	validUntil := netTime.Now().Add(time.Minute)
-	m.tracked = append(m.tracked, TrackedID{
+	m.tracked = append(m.tracked, &TrackedID{
 		NextGeneration: netTime.Now(),
 		LastGeneration: time.Time{},
 		Source:         testId,
diff --git a/cmix/interface.go b/cmix/interface.go
index 717dbb0bbe8b26a288aaa79427bc6d2ed07a30a6..f6572fb1dbdf6811052cb5d541e05286288c20cb 100644
--- a/cmix/interface.go
+++ b/cmix/interface.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package cmix
 
 import (
@@ -51,7 +58,7 @@ type Client interface {
 	// WARNING: Do not roll your own crypto.
 	Send(recipient *id.ID, fingerprint format.Fingerprint,
 		service message.Service, payload, mac []byte, cmixParams CMIXParams) (
-		id.Round, ephemeral.Id, error)
+		rounds.Round, ephemeral.Id, error)
 
 	// SendMany sends many "raw" cMix message payloads to the provided
 	// recipients all in the same round.
@@ -78,7 +85,25 @@ type Client interface {
 	// (along with the reason). Blocks until successful send or err.
 	// WARNING: Do not roll your own crypto.
 	SendMany(messages []TargetedCmixMessage, p CMIXParams) (
-		id.Round, []ephemeral.Id, error)
+		rounds.Round, []ephemeral.Id, error)
+
+	// SendWithAssembler sends a variable cmix payload to the provided recipient.
+	// The payload sent is based on the Complier function passed in, which accepts
+	// a round ID and returns the necessary payload data.
+	// Returns the round ID of the round the payload was sent or an error if it
+	// fails.
+	// This does not have end-to-end encryption on it and is used exclusively as
+	// a send for higher order cryptographic protocols. Do not use unless
+	// implementing a protocol on top.
+	//   recipient - cMix ID of the recipient.
+	//   assembler - MessageAssembler function, accepting round ID and returning
+	//   fingerprint
+	//   format.Fingerprint, service message.Service, payload, mac []byte
+	// Will return an error if the network is unhealthy or if it fails to send
+	// (along with the reason). Blocks until successful sends or errors.
+	// WARNING: Do not roll your own crypto.
+	SendWithAssembler(recipient *id.ID, assembler MessageAssembler,
+		cmixParams CMIXParams) (rounds.Round, ephemeral.Id, error)
 
 	/* === Message Reception ================================================ */
 	/* Identities are all network identities which the client is currently
@@ -229,7 +254,7 @@ type Client interface {
 	// GetRoundResults adjudicates on the rounds requested. Checks if they are
 	// older rounds or in progress rounds.
 	GetRoundResults(timeout time.Duration, roundCallback RoundEventCallback,
-		roundList ...id.Round) error
+		roundList ...id.Round)
 
 	// LookupHistoricalRound looks up the passed historical round on the network.
 	// GetRoundResults does this lookup when needed, generally that is
@@ -290,12 +315,15 @@ type Client interface {
 
 type ClientErrorReport func(source, message, trace string)
 
-// MessageAssembler func accepts a round ID, returning fingerprint, service, payload & mac.
-// This allows users to pass in a paylaod which will contain the round ID over which the message is sent.
-type MessageAssembler func(rid id.Round) (fingerprint format.Fingerprint, service message.Service, payload, mac []byte)
+// MessageAssembler func accepts a round ID, returning fingerprint, service,
+// payload & mac. This allows users to pass in a paylaod which will contain the
+// round ID over which the message is sent.
+type MessageAssembler func(rid id.Round) (fingerprint format.Fingerprint,
+	service message.Service, payload, mac []byte, err error)
 
-// messageAssembler is an internal wrapper around MessageAssembler which returns a format.message
-// This is necessary to preserve the interaction between sendCmixHelper and critical messages
+// messageAssembler is an internal wrapper around MessageAssembler which
+// returns a format.message This is necessary to preserve the interaction
+// between sendCmixHelper and critical messages
 type messageAssembler func(rid id.Round) (format.Message, error)
 
 type clientCommsInterface interface {
diff --git a/cmix/message/bundle.go b/cmix/message/bundle.go
index 887148285243b4eaa96c1d4b3ef2cdd74a137c0f..7e8b20fb943988e00e39e27bbc9dc68ed3145b14 100644
--- a/cmix/message/bundle.go
+++ b/cmix/message/bundle.go
@@ -1,15 +1,15 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package message
 
 import (
-	"gitlab.com/elixxir/client/cmix/rounds"
 	"gitlab.com/elixxir/client/cmix/identity/receptionID"
+	"gitlab.com/elixxir/client/cmix/rounds"
 	"gitlab.com/elixxir/primitives/format"
 	"gitlab.com/xx_network/primitives/id"
 )
diff --git a/cmix/message/fingerprints.go b/cmix/message/fingerprints.go
index bf6235b9711e6fe9930785ae6f941ab6290c30a5..656ab60e7942aa27f911ac0bd7d1845832c4494d 100644
--- a/cmix/message/fingerprints.go
+++ b/cmix/message/fingerprints.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package message
 
diff --git a/cmix/message/fingerprints_test.go b/cmix/message/fingerprints_test.go
index 813e48a5a4123dbff0995fbc1f51e1aa38b0848b..582480bd90973ce4e62102fa5f5319eeb1c55ca3 100644
--- a/cmix/message/fingerprints_test.go
+++ b/cmix/message/fingerprints_test.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package message
 
diff --git a/cmix/message/handler.go b/cmix/message/handler.go
index 6a5baf55486860b3d14d5d2960acaa861dc18ba0..45b693c5aba110a8c910148d59d75096b5d17fc6 100644
--- a/cmix/message/handler.go
+++ b/cmix/message/handler.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package message
 
diff --git a/cmix/message/handler_test.go b/cmix/message/handler_test.go
index 99dfb9f199d0ea3ced7341e0ae7282e73930feaf..33247a786a64b5fcadb01e7c62c5d5f88c2137cd 100644
--- a/cmix/message/handler_test.go
+++ b/cmix/message/handler_test.go
@@ -1,7 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2022 Privategrity Corporation                                   /
-//                                                                             /
-// All rights reserved.                                                        /
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package message
diff --git a/cmix/message/inProgress.go b/cmix/message/inProgress.go
index 83cc22fe27041c352bdfb73545e7113a9e5adb38..91760e5865ba99944e4d0b3b5ca78a4b393c34f1 100644
--- a/cmix/message/inProgress.go
+++ b/cmix/message/inProgress.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package message
 
diff --git a/cmix/message/inProgress_test.go b/cmix/message/inProgress_test.go
index be0dd901c40191e3523defc02457e016555cbf8e..c85dc5d0971324c43f502ed337ac6bd6d356e37b 100644
--- a/cmix/message/inProgress_test.go
+++ b/cmix/message/inProgress_test.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package message
 
 import (
diff --git a/cmix/message/meteredCmixMessageBuffer.go b/cmix/message/meteredCmixMessageBuffer.go
index 0c456e7c1c5846f63f3630778da8c2e109db614c..826f8cab50f4e645652229830a56afd459fd70ad 100644
--- a/cmix/message/meteredCmixMessageBuffer.go
+++ b/cmix/message/meteredCmixMessageBuffer.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package message
 
@@ -24,8 +24,6 @@ import (
 	"golang.org/x/crypto/blake2b"
 )
 
-const currentMeteredCmixMessageVersion = 0
-
 type meteredCmixMessageHandler struct{}
 
 type meteredCmixMessage struct {
@@ -49,13 +47,13 @@ func (*meteredCmixMessageHandler) SaveMessage(kv *versioned.KV, m interface{},
 
 	// Create versioned object
 	obj := versioned.Object{
-		Version:   currentMeteredCmixMessageVersion,
+		Version:   utility.CurrentMessageBufferVersion,
 		Timestamp: netTime.Now(),
 		Data:      marshaled,
 	}
 
 	// Save versioned object
-	return kv.Set(key, utility.CurrentMessageBufferVersion, &obj)
+	return kv.Set(key, &obj)
 }
 
 // LoadMessage returns the message with the specified key from the key value
@@ -64,7 +62,7 @@ func (*meteredCmixMessageHandler) SaveMessage(kv *versioned.KV, m interface{},
 func (*meteredCmixMessageHandler) LoadMessage(kv *versioned.KV, key string) (
 	interface{}, error) {
 	// Load the versioned object
-	vo, err := kv.Get(key, currentMeteredCmixMessageVersion)
+	vo, err := kv.Get(key, utility.CurrentMessageBufferVersion)
 	if err != nil {
 		return nil, err
 	}
@@ -83,7 +81,7 @@ func (*meteredCmixMessageHandler) LoadMessage(kv *versioned.KV, key string) (
 // DeleteMessage deletes the message with the specified key from the key value
 // store.
 func (*meteredCmixMessageHandler) DeleteMessage(kv *versioned.KV, key string) error {
-	return kv.Delete(key, currentMeteredCmixMessageVersion)
+	return kv.Delete(key, utility.CurrentMessageBufferVersion)
 }
 
 // HashMessage generates a hash of the message.
diff --git a/cmix/message/meteredCmixMessageBuffer_test.go b/cmix/message/meteredCmixMessageBuffer_test.go
index 3dbb7a65d2cb39232fd34abedf5a505b90056450..ec1d6f76e30265a988150e84e72dec012afa7010 100644
--- a/cmix/message/meteredCmixMessageBuffer_test.go
+++ b/cmix/message/meteredCmixMessageBuffer_test.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package message
 
diff --git a/cmix/message/params.go b/cmix/message/params.go
index cd2e6675bff9ad8eb6303b40c32a01f80ba152ea..61bc149c329f920e8afe523c7d0c3779b282d1fd 100644
--- a/cmix/message/params.go
+++ b/cmix/message/params.go
@@ -1,8 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package message
diff --git a/cmix/message/processor.go b/cmix/message/processor.go
index 1601189b65e1c6c8ea74c263e4e77e7531e76b8d..b59ef05bf593b56935cdd2e96e2c2bdc1eafad3c 100644
--- a/cmix/message/processor.go
+++ b/cmix/message/processor.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package message
 
 import (
diff --git a/cmix/message/serviceGenerators.go b/cmix/message/serviceGenerators.go
index 374e37ba17500c7ac59e25f5d3b6c9a9e7247136..b222063cdd01a7c51cd8825af12c012bbfaa0f97 100644
--- a/cmix/message/serviceGenerators.go
+++ b/cmix/message/serviceGenerators.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package message
 
 import (
diff --git a/cmix/message/serviceInterface.go b/cmix/message/serviceInterface.go
index 346ff4b7f3f05e5902912bd00ad450e2e5e9ff75..e596d6a67939665d0d74e18b519e85b6d4d8f720 100644
--- a/cmix/message/serviceInterface.go
+++ b/cmix/message/serviceInterface.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package message
 
 import (
diff --git a/cmix/message/serviceTracker.go b/cmix/message/serviceTracker.go
index 616f6dfda392ba4cb65c8d02179bbae493fe26ec..1b7d42ce7ef8aa16de2c2496aee1a3b3727ed5d4 100644
--- a/cmix/message/serviceTracker.go
+++ b/cmix/message/serviceTracker.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package message
 
 import (
@@ -26,7 +33,6 @@ func (sm *ServicesManager) triggerServiceTracking() {
 	if len(sm.trackers) == 0 {
 		return
 	}
-
 	services := make(ServiceList)
 	for uid, tmap := range sm.tmap {
 		tList := make([]Service, 0, len(tmap))
diff --git a/cmix/message/serviceTracker_test.go b/cmix/message/serviceTracker_test.go
index c7b06b46a853bcc23e267830c9e2cda925385b3a..27a3ac5cb3bcbf51397a074bdedd44f93e68a235 100644
--- a/cmix/message/serviceTracker_test.go
+++ b/cmix/message/serviceTracker_test.go
@@ -1,7 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2022 Privategrity Corporation                                   /
-//                                                                             /
-// All rights reserved.                                                        /
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package message
@@ -13,7 +14,7 @@ import (
 
 func TestServiceList_Marshal_UnmarshalJSON(t *testing.T) {
 	var sl ServiceList = make(map[id.ID][]Service)
-	numServices := 10
+	numServices := 3
 	testString := "test"
 	for i := 0; i < numServices; i++ {
 		uid := id.NewIdFromUInt(uint64(i), id.User, t)
@@ -24,6 +25,8 @@ func TestServiceList_Marshal_UnmarshalJSON(t *testing.T) {
 		t.Errorf(err.Error())
 	}
 
+	t.Logf("%s", jsonResult)
+
 	sl = make(map[id.ID][]Service)
 	err = sl.UnmarshalJSON(jsonResult)
 	if err != nil {
diff --git a/cmix/message/services.go b/cmix/message/services.go
index 9ede26311cff79aca197228ed51ce3c388b1f7ae..665c4f858dfb2b0af472cd08a4fbdb436df000f0 100644
--- a/cmix/message/services.go
+++ b/cmix/message/services.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package message
 
diff --git a/cmix/message/services_test.go b/cmix/message/services_test.go
index e3cad7bed0e9ef7d2e21a1561d8cf977213bfb1b..d2082c63ce32dad5c689892457d4e42a9f3e1923 100644
--- a/cmix/message/services_test.go
+++ b/cmix/message/services_test.go
@@ -1,7 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2022 Privategrity Corporation                                   /
-//                                                                             /
-// All rights reserved.                                                        /
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package message
diff --git a/cmix/nodes/interfaces.go b/cmix/nodes/interfaces.go
index ba5809881cf9a7cddc658176b8898eb9f6378bd2..5d08e6db9a6c97712621ed02ced970e8344e1f00 100644
--- a/cmix/nodes/interfaces.go
+++ b/cmix/nodes/interfaces.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package nodes
 
diff --git a/cmix/nodes/mixCypher.go b/cmix/nodes/mixCypher.go
index 7afc8f23de227e170e6ef5d3f0d797b5dbbff5f5..ab3a554cc9dc39c27cc63e0893e3e26dcf2bd0fb 100644
--- a/cmix/nodes/mixCypher.go
+++ b/cmix/nodes/mixCypher.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package nodes
 
diff --git a/cmix/nodes/mixCypher_test.go b/cmix/nodes/mixCypher_test.go
index 941ee5532b07edcb84f89888600322e8822555f5..491ef481dfec6422a3f269b31c4bfd2f9911e78b 100644
--- a/cmix/nodes/mixCypher_test.go
+++ b/cmix/nodes/mixCypher_test.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package nodes
 
diff --git a/cmix/nodes/register.go b/cmix/nodes/register.go
index 000b5751501b8120c35f099f3a2db59257a8fb07..5d2249ec617e7d39af16bcdd58cc0bd0d7879558 100644
--- a/cmix/nodes/register.go
+++ b/cmix/nodes/register.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package nodes
 
diff --git a/cmix/nodes/register_test.go b/cmix/nodes/register_test.go
index 6f87c165af189030f5414adc6f61275af3f0add7..8ed9e6c897869e8ad9b5142b20a0e66e992b5621 100644
--- a/cmix/nodes/register_test.go
+++ b/cmix/nodes/register_test.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package nodes
 
@@ -88,4 +88,3 @@ func TestRegisterWithNode(t *testing.T) {
 		t.Fatalf("registerWithNode error: %+v", err)
 	}
 }
-
diff --git a/cmix/nodes/registrar.go b/cmix/nodes/registrar.go
index 2bfa2cb5df2d982e650658ce15e938d3e31c4624..dc61852f183937b5f4f9eadcda2cdfacd28d20a9 100644
--- a/cmix/nodes/registrar.go
+++ b/cmix/nodes/registrar.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package nodes
 
 import (
diff --git a/cmix/nodes/registrar_test.go b/cmix/nodes/registrar_test.go
index ded004b220cf4e394d2290b842fb2187eb81459b..922adfad68bc2b52f999a92561c834803be4f16b 100644
--- a/cmix/nodes/registrar_test.go
+++ b/cmix/nodes/registrar_test.go
@@ -1,8 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package nodes
diff --git a/cmix/nodes/request.go b/cmix/nodes/request.go
index 4a99c358427314446ccd557afe9596f15ffd7440..499acb4550b2ff31ebf2e4a2d4a8f8c0ef1c707b 100644
--- a/cmix/nodes/request.go
+++ b/cmix/nodes/request.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package nodes
 
 import (
diff --git a/cmix/nodes/store.go b/cmix/nodes/store.go
index ff4511934e02bf57c78834de19c1bc99ea3ac0b1..8ec0e706b1e637d8272fac785c68f5905f98a23e 100644
--- a/cmix/nodes/store.go
+++ b/cmix/nodes/store.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package nodes
 
@@ -67,12 +67,12 @@ func (r *registrar) save() error {
 	}
 
 	obj := versioned.Object{
-		Version:   currentStoreVersion,
+		Version:   currentKeyVersion,
 		Timestamp: now,
 		Data:      data,
 	}
 
-	return r.kv.Set(storeKey, currentKeyVersion, &obj)
+	return r.kv.Set(storeKey, &obj)
 }
 
 // marshal builds a byte representation of the registrar.
diff --git a/cmix/nodes/storeKey.go b/cmix/nodes/storeKey.go
index 98b6e18cac27c1611bf6f6e2f01a2cf38551a3d2..19f9a636c69102926966ec2f3a53f759d2df4032 100644
--- a/cmix/nodes/storeKey.go
+++ b/cmix/nodes/storeKey.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package nodes
 
@@ -84,7 +84,7 @@ func (k *key) save() error {
 		Data:      data,
 	}
 
-	return k.kv.Set(k.storeKey, currentKeyVersion, &obj)
+	return k.kv.Set(k.storeKey, &obj)
 }
 
 // delete deletes the key from the versioned keystore.
diff --git a/cmix/nodes/store_test.go b/cmix/nodes/store_test.go
index 58ecbd9e602896816e0ff3023b826eb957478693..05bc38b2060bbfbd7ff32ad0f132d793aadb525b 100644
--- a/cmix/nodes/store_test.go
+++ b/cmix/nodes/store_test.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package nodes
 
diff --git a/cmix/nodes/utils_test.go b/cmix/nodes/utils_test.go
index 5370705a4a72e11638a98b5f54d7aaa15800f9d5..96eacda72794e3f66c1b4513e7f359624cf0cbe1 100644
--- a/cmix/nodes/utils_test.go
+++ b/cmix/nodes/utils_test.go
@@ -1,8 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package nodes
diff --git a/cmix/params.go b/cmix/params.go
index 73ec67dd10f47bb5969164e8593687cac5cf0e16..8eb6c6c3c96d7edd28dac004bfc57df0a1d0d2f3 100644
--- a/cmix/params.go
+++ b/cmix/params.go
@@ -1,8 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package cmix
@@ -58,6 +58,10 @@ type Params struct {
 	// times.
 	ReplayRequests bool
 
+	// MaxParallelIdentityTracks is the maximum number of parallel identities
+	// the system will poll in one iteration of the follower
+	MaxParallelIdentityTracks uint
+
 	Rounds     rounds.Params
 	Pickup     pickup.Params
 	Message    message.Params
@@ -80,6 +84,7 @@ type paramsDisk struct {
 	Pickup                    pickup.Params
 	Message                   message.Params
 	Historical                rounds.Params
+	MaxParallelIdentityTracks uint
 }
 
 // GetDefaultParams returns a Params object containing the
@@ -96,6 +101,7 @@ func GetDefaultParams() Params {
 		VerboseRoundTracking:      false,
 		RealtimeOnly:              false,
 		ReplayRequests:            true,
+		MaxParallelIdentityTracks: 20,
 	}
 	n.Rounds = rounds.GetDefaultParams()
 	n.Pickup = pickup.GetDefaultParams()
@@ -135,6 +141,7 @@ func (p Params) MarshalJSON() ([]byte, error) {
 		Pickup:                    p.Pickup,
 		Message:                   p.Message,
 		Historical:                p.Historical,
+		MaxParallelIdentityTracks: p.MaxParallelIdentityTracks,
 	}
 
 	return json.Marshal(&pDisk)
@@ -163,6 +170,7 @@ func (p *Params) UnmarshalJSON(data []byte) error {
 		Pickup:                    pDisk.Pickup,
 		Message:                   pDisk.Message,
 		Historical:                pDisk.Historical,
+		MaxParallelIdentityTracks: pDisk.MaxParallelIdentityTracks,
 	}
 
 	return nil
diff --git a/cmix/params_test.go b/cmix/params_test.go
index 90ece9d5f6ff0dbf23a528832a0adc297425818e..a6eec124db47ec5a981dba499283708bc8cfcb40 100644
--- a/cmix/params_test.go
+++ b/cmix/params_test.go
@@ -1,8 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package cmix
diff --git a/cmix/pickup/get.go b/cmix/pickup/get.go
index f7a503b1d9fbc360a547f56a877372800db3a545..a31fb36300a2b116ef17ceec9d7eb7e401aef644 100644
--- a/cmix/pickup/get.go
+++ b/cmix/pickup/get.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package pickup
 
diff --git a/cmix/pickup/params.go b/cmix/pickup/params.go
index 99ec4cb835557f411d3d88cdf07acc23e40dba14..84754d38f4f741350da8c37d0a6f708e3e41bcee 100644
--- a/cmix/pickup/params.go
+++ b/cmix/pickup/params.go
@@ -1,8 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package pickup
diff --git a/cmix/pickup/pickup.go b/cmix/pickup/pickup.go
index 649ab4ae0dcdac73615ef501831c67146d327c08..581aeaf285553f55586a5c6006a93dc64f941203 100644
--- a/cmix/pickup/pickup.go
+++ b/cmix/pickup/pickup.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package pickup
 
diff --git a/cmix/pickup/retrieve.go b/cmix/pickup/retrieve.go
index a855e1e8a641a98cc99a62827caf9be15ca95347..45c8a7e3f66c2d321fbd3882acb40f4ed8e3c9ea 100644
--- a/cmix/pickup/retrieve.go
+++ b/cmix/pickup/retrieve.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package pickup
 
diff --git a/cmix/pickup/retrieve_test.go b/cmix/pickup/retrieve_test.go
index cf580ec420dfb8d0e3f6a2c62b774f7e5f637479..a14b34a4cadce84b4b73b0447f163355b6138cc1 100644
--- a/cmix/pickup/retrieve_test.go
+++ b/cmix/pickup/retrieve_test.go
@@ -1,9 +1,10 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package pickup
 
 import (
diff --git a/cmix/pickup/roundGetter.go b/cmix/pickup/roundGetter.go
index 9f01fa4971fb7a02fa9176bed730c47fa66e2d2f..1c265b286c66df0921d41174a594a37d74a35a7d 100644
--- a/cmix/pickup/roundGetter.go
+++ b/cmix/pickup/roundGetter.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package pickup
 
 import (
diff --git a/cmix/pickup/store/roundIdentity.go b/cmix/pickup/store/roundIdentity.go
index a5c64b021d999a7ab78437e5b190c715e4620696..c9fc5df6cebdecee740ceb4cce079d34782fbe12 100644
--- a/cmix/pickup/store/roundIdentity.go
+++ b/cmix/pickup/store/roundIdentity.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package store
 
 import (
diff --git a/cmix/pickup/store/store.go b/cmix/pickup/store/store.go
index 4a1f83006a2dce8fead22551dcebfabb2127ad61..88a300494aaa2003c3181c60cec46b6c6e884821 100644
--- a/cmix/pickup/store/store.go
+++ b/cmix/pickup/store/store.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package store
 
 import (
@@ -218,7 +225,7 @@ func (s *UncheckedRoundStore) save() error {
 	}
 
 	// Save to storage
-	err = s.kv.Set(uncheckedRoundKey, uncheckedRoundVersion, obj)
+	err = s.kv.Set(uncheckedRoundKey, obj)
 	if err != nil {
 		return errors.WithMessagef(err,
 			"Could not store data for unchecked rounds")
diff --git a/cmix/pickup/store/uncheckedRounds.go b/cmix/pickup/store/uncheckedRounds.go
index b15cc5b803cc9d3139746833c60b6baf14e5ac35..bc62d8a1d64583c44ca690af23aa733ee2e742e8 100644
--- a/cmix/pickup/store/uncheckedRounds.go
+++ b/cmix/pickup/store/uncheckedRounds.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package store
 
@@ -147,7 +147,7 @@ func storeRoundInfo(kv *versioned.KV, info *pb.RoundInfo, recipient *id.ID,
 	}
 
 	return kv.Set(
-		roundKey(id.Round(info.ID), recipient, ephID), roundInfoVersion, &obj)
+		roundKey(id.Round(info.ID), recipient, ephID), &obj)
 }
 
 func loadRoundInfo(kv *versioned.KV, id id.Round, recipient *id.ID,
diff --git a/cmix/pickup/store/uncheckedRounds_test.go b/cmix/pickup/store/uncheckedRounds_test.go
index 8e4dbe052e75d5eb98fb98863be92d91200c54b4..2f8354b09e6df0fa244d6299c34ca96ce160da4e 100644
--- a/cmix/pickup/store/uncheckedRounds_test.go
+++ b/cmix/pickup/store/uncheckedRounds_test.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package store
 
diff --git a/cmix/pickup/unchecked.go b/cmix/pickup/unchecked.go
index 22afaa5658b79604b1feebadf2a73312b41d952a..ca289a1ee390bfb7dd9df3c634590d8a54be7752 100644
--- a/cmix/pickup/unchecked.go
+++ b/cmix/pickup/unchecked.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package pickup
 
diff --git a/cmix/pickup/unchecked_test.go b/cmix/pickup/unchecked_test.go
index 339826469fc28b0797788db62e63e4a7f110cb5a..6db1b9ec67c2f767cf04e0d170325173622f0c52 100644
--- a/cmix/pickup/unchecked_test.go
+++ b/cmix/pickup/unchecked_test.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package pickup
 
diff --git a/cmix/pickup/utils_test.go b/cmix/pickup/utils_test.go
index d25491d283b2ec59fc17834d8101f193e9f6ff53..2b325987ac6fab5a1bcfd205a10ba25837f53a2e 100644
--- a/cmix/pickup/utils_test.go
+++ b/cmix/pickup/utils_test.go
@@ -1,9 +1,10 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package pickup
 
 import (
diff --git a/cmix/polltracker.go b/cmix/polltracker.go
index 835a820c548137965d0566178f22cc397c862881..1e0bdcb453c8374b199392c3941910b5108071da 100644
--- a/cmix/polltracker.go
+++ b/cmix/polltracker.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package cmix
 
 import (
diff --git a/cmix/polltracker_test.go b/cmix/polltracker_test.go
index 8fb6d96860d70c94f48f51843a03df44f84694be..1c10c9f9dba590a67b7213b89b13b1f26d93aae9 100644
--- a/cmix/polltracker_test.go
+++ b/cmix/polltracker_test.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package cmix
 
 import (
diff --git a/cmix/remoteFilters.go b/cmix/remoteFilters.go
index 37cf100e60396c612df73e85b31e5d07c5688d2f..4610697fec850387eb15f49c89024336d187e973 100644
--- a/cmix/remoteFilters.go
+++ b/cmix/remoteFilters.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package cmix
 
diff --git a/cmix/remoteFilters_test.go b/cmix/remoteFilters_test.go
index b33daa8b4904ec557857724609433b8baf33b8e2..97b8b9040e67d5a611b6ba2c26c6bdc5fab7d9dd 100644
--- a/cmix/remoteFilters_test.go
+++ b/cmix/remoteFilters_test.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package cmix
 
diff --git a/cmix/results.go b/cmix/results.go
index a6f8c4ad8834925dd54af6a8f151b750d0f092e8..916bdb206610fc2c98ed0509acba705d6c9c1a33 100644
--- a/cmix/results.go
+++ b/cmix/results.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package cmix
 
@@ -65,19 +65,19 @@ type RoundEventCallback func(allRoundsSucceeded, timedOut bool, rounds map[id.Ro
 // GetRoundResults adjudicates on the rounds requested. Checks if they are
 // older rounds or in progress rounds.
 func (c *client) GetRoundResults(timeout time.Duration,
-	roundCallback RoundEventCallback, roundList ...id.Round) error {
+	roundCallback RoundEventCallback, roundList ...id.Round) {
 
 	jww.INFO.Printf("GetRoundResults(%v, %s)", roundList, timeout)
 
 	sendResults := make(chan ds.EventReturn, len(roundList))
 
-	return c.getRoundResults(roundList, timeout, roundCallback,
+	c.getRoundResults(roundList, timeout, roundCallback,
 		sendResults)
 }
 
 // Helper function which does all the logic for GetRoundResults
 func (c *client) getRoundResults(roundList []id.Round, timeout time.Duration,
-	roundCallback RoundEventCallback, sendResults chan ds.EventReturn) error {
+	roundCallback RoundEventCallback, sendResults chan ds.EventReturn) {
 
 	networkInstance := c.GetInstance()
 
@@ -221,6 +221,4 @@ func (c *client) getRoundResults(roundList []id.Round, timeout time.Duration,
 
 		}
 	}()
-
-	return nil
 }
diff --git a/cmix/results_test.go b/cmix/results_test.go
index eaa2edb2b8de79d4caf49cada4c8e95123ca5c03..d0de5e992a2cc5657a299648644248cd7cb234d7 100644
--- a/cmix/results_test.go
+++ b/cmix/results_test.go
@@ -1,9 +1,10 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package cmix
 
 const numRounds = 10
diff --git a/cmix/roundTracking.go b/cmix/roundTracking.go
index 56b327d17b309bc700af2dcc2f05a6d005eb37dd..674538a1a405dd02b335a59474cce7afd5bcc739 100644
--- a/cmix/roundTracking.go
+++ b/cmix/roundTracking.go
@@ -1,7 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2021 Privategrity Corporation                                   /
-//                                                                             /
-// All rights reserved.                                                        /
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 // This is an in-memory track of rounds that have been processed in this run of
diff --git a/cmix/roundTracking_test.go b/cmix/roundTracking_test.go
index c6219228a6e6df2c3d2c39a69440fa43e20e9013..9e7760458a429fac91bc1090876e47da2d91064d 100644
--- a/cmix/roundTracking_test.go
+++ b/cmix/roundTracking_test.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package cmix
 
 import (
diff --git a/cmix/rounds/historical.go b/cmix/rounds/historical.go
index 6b4ffbcd727c9b2e8c70b53769fb44c46761dca7..165ce22817fd2e9e01dda3de8c410ab0c174f40c 100644
--- a/cmix/rounds/historical.go
+++ b/cmix/rounds/historical.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package rounds
 
diff --git a/cmix/rounds/historical_test.go b/cmix/rounds/historical_test.go
index 807386a2557bcc84392e024d99d1ca0aedc30e1d..7fec1ae6629ba7bbb6640d4d17acddc96a480fc9 100644
--- a/cmix/rounds/historical_test.go
+++ b/cmix/rounds/historical_test.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package rounds
 
diff --git a/cmix/rounds/params.go b/cmix/rounds/params.go
index dd9596c2fcf6809010ceb9fbeda609f2ef3b6645..78a407a75193f54be463ba08eb557f5215cb0a79 100644
--- a/cmix/rounds/params.go
+++ b/cmix/rounds/params.go
@@ -1,8 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package rounds
diff --git a/cmix/rounds/round.go b/cmix/rounds/round.go
index 6f4f48183ca2c2f0eb0e473f4a91a752fa381b11..850cfb99e2b1ad2ac2a407b287c273ffa4211a20 100644
--- a/cmix/rounds/round.go
+++ b/cmix/rounds/round.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package rounds
 
 import (
diff --git a/cmix/rounds/roundStorage.go b/cmix/rounds/roundStorage.go
index 2b92c819f9b6279dd30d4b8b37a503b146168501..f05914ba2918612c1cb382e95e870f7c6fc7157c 100644
--- a/cmix/rounds/roundStorage.go
+++ b/cmix/rounds/roundStorage.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package rounds
 
 import (
@@ -25,7 +32,7 @@ func StoreRound(kv *versioned.KV, round Round, key string) error {
 		Data:      marshaled,
 	}
 
-	return kv.Set(key, currentRoundVersion, &obj)
+	return kv.Set(key, &obj)
 }
 
 // LoadRound stores the round using the key.
diff --git a/cmix/rounds/round_test.go b/cmix/rounds/round_test.go
index b0198c9acf473e2c70eae144ff71cdc3b9d96412..e903a5968e0874900296ee7211706d87afb216c3 100644
--- a/cmix/rounds/round_test.go
+++ b/cmix/rounds/round_test.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package rounds
 
 import (
diff --git a/cmix/sendCmix.go b/cmix/sendCmix.go
index 648e1ef1c8691211f40bf11fc76e86bc17e5dfe7..bc9891a4abfea507ebe4f18672fbd72ab8270a3c 100644
--- a/cmix/sendCmix.go
+++ b/cmix/sendCmix.go
@@ -1,14 +1,15 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package cmix
 
 import (
 	"fmt"
+	"gitlab.com/elixxir/client/cmix/rounds"
 	"strings"
 	"time"
 
@@ -56,10 +57,11 @@ import (
 // WARNING: Do not roll your own crypto.
 func (c *client) Send(recipient *id.ID, fingerprint format.Fingerprint,
 	service message.Service, payload, mac []byte, cmixParams CMIXParams) (
-	id.Round, ephemeral.Id, error) {
+	rounds.Round, ephemeral.Id, error) {
 	// create an internal assembler function to pass to sendWithAssembler
-	assembler := func(rid id.Round) (format.Fingerprint, message.Service, []byte, []byte) {
-		return fingerprint, service, payload, mac
+	assembler := func(rid id.Round) (format.Fingerprint, message.Service,
+		[]byte, []byte, error) {
+		return fingerprint, service, payload, mac, nil
 	}
 	return c.sendWithAssembler(recipient, assembler, cmixParams)
 }
@@ -79,10 +81,10 @@ func (c *client) Send(recipient *id.ID, fingerprint format.Fingerprint,
 // (along with the reason). Blocks until successful sends or errors.
 // WARNING: Do not roll your own crypto.
 func (c *client) SendWithAssembler(recipient *id.ID, assembler MessageAssembler, cmixParams CMIXParams) (
-	id.Round, ephemeral.Id, error) {
+	rounds.Round, ephemeral.Id, error) {
 	// Critical messaging and assembler-based message payloads are not compatible
 	if cmixParams.Critical {
-		return 0, ephemeral.Id{}, errors.New("Cannot send critical messages with a message assembler")
+		return rounds.Round{}, ephemeral.Id{}, errors.New("Cannot send critical messages with a message assembler")
 	}
 	return c.sendWithAssembler(recipient, assembler, cmixParams)
 }
@@ -90,15 +92,19 @@ func (c *client) SendWithAssembler(recipient *id.ID, assembler MessageAssembler,
 // sendWithAssembler wraps the passed in MessageAssembler in a messageAssembler for sendCmixHelper,
 // and sets up critical message handling where applicable.
 func (c *client) sendWithAssembler(recipient *id.ID, assembler MessageAssembler, cmixParams CMIXParams) (
-	id.Round, ephemeral.Id, error) {
+	rounds.Round, ephemeral.Id, error) {
 	if !c.Monitor.IsHealthy() {
-		return 0, ephemeral.Id{}, errors.New(
+		return rounds.Round{}, ephemeral.Id{}, errors.New(
 			"Cannot send cmix message when the network is not healthy")
 	}
 
 	// Create an internal messageAssembler which returns a format.Message
 	assemblerFunc := func(rid id.Round) (format.Message, error) {
-		fingerprint, service, payload, mac := assembler(rid)
+		fingerprint, service, payload, mac, err := assembler(rid)
+
+		if err != nil {
+			return format.Message{}, err
+		}
 
 		if len(payload) != c.maxMsgLen {
 			return format.Message{}, errors.Errorf(
@@ -123,15 +129,15 @@ func (c *client) sendWithAssembler(recipient *id.ID, assembler MessageAssembler,
 		return msg, nil
 	}
 
-	rid, ephID, msg, rtnErr := sendCmixHelper(c.Sender, assemblerFunc, recipient, cmixParams,
+	r, ephID, msg, rtnErr := sendCmixHelper(c.Sender, assemblerFunc, recipient, cmixParams,
 		c.instance, c.session.GetCmixGroup(), c.Registrar, c.rng, c.events,
 		c.session.GetTransmissionID(), c.comms)
 
 	if cmixParams.Critical {
-		c.crit.handle(msg, recipient, rid, rtnErr)
+		c.crit.handle(msg, recipient, r.ID, rtnErr)
 	}
 
-	return rid, ephID, rtnErr
+	return r, ephID, rtnErr
 }
 
 // sendCmixHelper is a helper function for client.SendCMIX.
@@ -147,7 +153,13 @@ func (c *client) sendWithAssembler(recipient *id.ID, assembler MessageAssembler,
 func sendCmixHelper(sender gateway.Sender, assembler messageAssembler, recipient *id.ID,
 	cmixParams CMIXParams, instance *network.Instance, grp *cyclic.Group,
 	nodes nodes.Registrar, rng *fastRNG.StreamGenerator, events event.Reporter,
-	senderId *id.ID, comms SendCmixCommsInterface) (id.Round, ephemeral.Id, format.Message, error) {
+	senderId *id.ID, comms SendCmixCommsInterface) (rounds.Round, ephemeral.Id, format.Message, error) {
+
+	if cmixParams.RoundTries == 0 {
+		return rounds.Round{}, ephemeral.Id{}, format.Message{},
+			errors.Errorf("invalid parameter set, "+
+				"RoundTries cannot be 0: %+v", cmixParams)
+	}
 
 	timeStart := netTime.Now()
 	maxTimeout := sender.GetHostParams().SendTimeout
@@ -165,7 +177,8 @@ func sendCmixHelper(sender gateway.Sender, assembler messageAssembler, recipient
 	stream := rng.GetStream()
 	defer stream.Close()
 
-	for numRoundTries := uint(0); numRoundTries < cmixParams.RoundTries; numRoundTries++ {
+	for numRoundTries := uint(
+		0); numRoundTries < cmixParams.RoundTries; numRoundTries++ {
 		elapsed := netTime.Since(timeStart)
 		jww.TRACE.Printf("[Send-%s] try %d, elapsed: %s",
 			cmixParams.DebugTag, numRoundTries, elapsed)
@@ -174,7 +187,7 @@ func sendCmixHelper(sender gateway.Sender, assembler messageAssembler, recipient
 			jww.INFO.Printf("[Send-%s] No rounds to send to %s "+
 				"were found before timeout %s",
 				cmixParams.DebugTag, recipient, cmixParams.Timeout)
-			return 0, ephemeral.Id{}, format.Message{}, errors.New("Sending cmix message timed out")
+			return rounds.Round{}, ephemeral.Id{}, format.Message{}, errors.New("Sending cmix message timed out")
 		}
 
 		if numRoundTries > 0 {
@@ -185,30 +198,34 @@ func sendCmixHelper(sender gateway.Sender, assembler messageAssembler, recipient
 
 		// Find the best round to send to, excluding attempted rounds
 		remainingTime := cmixParams.Timeout - elapsed
-		bestRound, err := instance.GetWaitingRounds().GetUpcomingRealtime(
+		waitingRounds := instance.GetWaitingRounds()
+		bestRound, err := waitingRounds.GetUpcomingRealtime(
 			remainingTime, attempted, sendTimeBuffer)
 		if err != nil {
-			jww.WARN.Printf("[Send-%s] Failed to GetUpcomingRealtime: "+
+			jww.WARN.Printf("[Send-%s] failed to GetUpcomingRealtime: "+
 				"%+v", cmixParams.DebugTag, err)
 		}
 
 		if bestRound == nil {
 			jww.WARN.Printf(
-				"[Send-%s] Best round on send is nil", cmixParams.DebugTag)
+				"[Send-%s] Best round on send is nil",
+				cmixParams.DebugTag)
 			continue
 		}
 
 		jww.TRACE.Printf("[Send-%s] Best round found: %+v",
 			cmixParams.DebugTag, bestRound)
 
-		// Determine whether the selected round contains any nodes that are
-		// blacklisted by the CMIXParams object
+		// Determine whether the selected round contains any
+		// nodes that are blacklisted by the CMIXParams object
 		containsBlacklisted := false
 		if cmixParams.BlacklistedNodes != nil {
+			blacklist := cmixParams.BlacklistedNodes
 			for _, nodeId := range bestRound.Topology {
 				var nid id.ID
 				copy(nid[:], nodeId)
-				if _, isBlacklisted := cmixParams.BlacklistedNodes[nid]; isBlacklisted {
+				_, isBlacklisted := blacklist[nid]
+				if isBlacklisted {
 					containsBlacklisted = true
 					break
 				}
@@ -216,15 +233,17 @@ func sendCmixHelper(sender gateway.Sender, assembler messageAssembler, recipient
 		}
 
 		if containsBlacklisted {
-			jww.WARN.Printf("[Send-%s] Round %d contains blacklisted "+
-				"nodes, skipping...", cmixParams.DebugTag, bestRound.ID)
+			jww.WARN.Printf("[Send-%s] Round %d "+
+				"contains blacklisted nodes, skipping...",
+				cmixParams.DebugTag,
+				bestRound.ID)
 			continue
 		}
 
 		msg, err := assembler(id.Round(bestRound.ID))
 		if err != nil {
 			jww.ERROR.Printf("Failed to compile message: %+v", err)
-			return 0, ephemeral.Id{}, format.Message{}, err
+			return rounds.Round{}, ephemeral.Id{}, format.Message{}, err
 		}
 
 		// Flip leading bits randomly to thwart a tagging attack.
@@ -247,7 +266,7 @@ func sendCmixHelper(sender gateway.Sender, assembler messageAssembler, recipient
 		wrappedMsg, encMsg, ephID, err := buildSlotMessage(msg, recipient,
 			firstGateway, stream, senderId, bestRound, roundKeys)
 		if err != nil {
-			return 0, ephemeral.Id{}, format.Message{}, err
+			return rounds.Round{}, ephemeral.Id{}, format.Message{}, err
 		}
 
 		jww.INFO.Printf("[Send-%s] Sending to EphID %d (%s), on round %d "+
@@ -297,7 +316,7 @@ func sendCmixHelper(sender gateway.Sender, assembler messageAssembler, recipient
 
 		// Exit if the thread has been stopped
 		if stoppable.CheckErr(err) {
-			return 0, ephemeral.Id{}, format.Message{}, err
+			return rounds.Round{}, ephemeral.Id{}, format.Message{}, err
 		}
 
 		// If the comm errors or the message fails to send, continue retrying
@@ -306,7 +325,7 @@ func sendCmixHelper(sender gateway.Sender, assembler messageAssembler, recipient
 				jww.ERROR.Printf("[Send-%s] SendCmix failed to send to "+
 					"EphID %d (%s) on round %d: %+v", cmixParams.DebugTag,
 					ephID.Int64(), recipient, bestRound.ID, err)
-				return 0, ephemeral.Id{}, format.Message{}, err
+				return rounds.Round{}, ephemeral.Id{}, format.Message{}, err
 			}
 
 			jww.ERROR.Printf("[Send-%s] SendCmix failed to send to "+
@@ -326,7 +345,7 @@ func sendCmixHelper(sender gateway.Sender, assembler messageAssembler, recipient
 			jww.INFO.Print(m)
 			events.Report(1, "MessageSend", "Metric", m)
 
-			return id.Round(bestRound.ID), ephID, msg, nil
+			return rounds.MakeRound(bestRound), ephID, msg, nil
 		} else {
 			jww.FATAL.Panicf("[Send-%s] Gateway %s returned no error, "+
 				"but failed to accept message when sending to EphID %d (%s) "+
@@ -335,6 +354,6 @@ func sendCmixHelper(sender gateway.Sender, assembler messageAssembler, recipient
 		}
 
 	}
-	return 0, ephemeral.Id{}, format.Message{},
-		errors.New("failed to send the message, unknown error")
+	return rounds.Round{}, ephemeral.Id{}, format.Message{},
+		errors.New("failed to send the message, out of round retries")
 }
diff --git a/cmix/sendCmixUtils.go b/cmix/sendCmixUtils.go
index e1db33471e869d36e60369813746c59c8bb44b11..146e63117d5cde18c1ee8d9dc794156eded72ad1 100644
--- a/cmix/sendCmixUtils.go
+++ b/cmix/sendCmixUtils.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package cmix
 
diff --git a/cmix/sendCmix_test.go b/cmix/sendCmix_test.go
index 67ec64ef857f9220adb3d23998aef44442631ba3..9b08c71f703729d983c2efdbbdac38b3017ac04d 100644
--- a/cmix/sendCmix_test.go
+++ b/cmix/sendCmix_test.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package cmix
 
 // func TestClient_SendCMIX(t *testing.T) {
diff --git a/cmix/sendManyCmix.go b/cmix/sendManyCmix.go
index 01e39d34e881167e224ae78fe65a8bbc18aacee0..b9700c0d813a15754713a322b96422e484c24f3e 100644
--- a/cmix/sendManyCmix.go
+++ b/cmix/sendManyCmix.go
@@ -1,14 +1,15 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package cmix
 
 import (
 	"fmt"
+	"gitlab.com/elixxir/client/cmix/rounds"
 	"strings"
 	"time"
 
@@ -67,9 +68,9 @@ type TargetedCmixMessage struct {
 // (along with the reason). Blocks until successful send or err.
 // WARNING: Do not roll your own crypto
 func (c *client) SendMany(messages []TargetedCmixMessage,
-	p CMIXParams) (id.Round, []ephemeral.Id, error) {
+	p CMIXParams) (rounds.Round, []ephemeral.Id, error) {
 	if !c.Monitor.IsHealthy() {
-		return 0, []ephemeral.Id{}, errors.New(
+		return rounds.Round{}, []ephemeral.Id{}, errors.New(
 			"Cannot send cMix message when the network is not healthy")
 	}
 
@@ -113,7 +114,7 @@ func sendManyCmixHelper(sender gateway.Sender,
 	grp *cyclic.Group, registrar nodes.Registrar,
 	rng *fastRNG.StreamGenerator, events event.Reporter,
 	senderId *id.ID, comms SendCmixCommsInterface) (
-	id.Round, []ephemeral.Id, error) {
+	rounds.Round, []ephemeral.Id, error) {
 
 	timeStart := netTime.Now()
 	var attempted excludedRounds.ExcludedRounds
@@ -147,7 +148,7 @@ func sendManyCmixHelper(sender gateway.Sender,
 			jww.INFO.Printf("[SendMany-%s] No rounds to send to %s "+
 				"(msgDigest: %s) were found before timeout %s", param.DebugTag,
 				recipientString, msgDigests, param.Timeout)
-			return 0, []ephemeral.Id{},
+			return rounds.Round{}, []ephemeral.Id{},
 				errors.New("sending cMix message timed out")
 		}
 
@@ -210,7 +211,7 @@ func sendManyCmixHelper(sender gateway.Sender,
 				stream.Close()
 				jww.INFO.Printf("[SendMany-%s] Error building slot "+
 					"received: %v", param.DebugTag, err)
-				return 0, []ephemeral.Id{}, errors.Errorf("failed to build "+
+				return rounds.Round{}, []ephemeral.Id{}, errors.Errorf("failed to build "+
 					"slot message for %s: %+v", msg.Recipient, err)
 			}
 		}
@@ -259,7 +260,7 @@ func sendManyCmixHelper(sender gateway.Sender,
 
 		// Exit if the thread has been stopped
 		if stoppable.CheckErr(err) {
-			return 0, []ephemeral.Id{}, err
+			return rounds.Round{}, []ephemeral.Id{}, err
 		}
 
 		// If the comm errors or the message fails to send, continue retrying
@@ -276,7 +277,7 @@ func sendManyCmixHelper(sender gateway.Sender,
 				jww.INFO.Printf("[SendMany-%s] Error received: %v",
 					param.DebugTag, err)
 			}
-			return 0, []ephemeral.Id{}, err
+			return rounds.Round{}, []ephemeral.Id{}, err
 		}
 
 		// Return if it sends properly
@@ -288,7 +289,7 @@ func sendManyCmixHelper(sender gateway.Sender,
 				bestRound.ID, msgDigests)
 			jww.INFO.Print(m)
 			events.Report(1, "MessageSendMany", "Metric", m)
-			return id.Round(bestRound.ID), ephemeralIDs, nil
+			return rounds.MakeRound(bestRound), ephemeralIDs, nil
 		} else {
 			jww.FATAL.Panicf("[SendMany-%s] Gateway %s returned no "+
 				"error, but failed to accept message when sending to EphIDs "+
@@ -297,6 +298,6 @@ func sendManyCmixHelper(sender gateway.Sender,
 		}
 	}
 
-	return 0, []ephemeral.Id{},
+	return rounds.Round{}, []ephemeral.Id{},
 		errors.New("failed to send the message, unknown error")
 }
diff --git a/cmix/sendManyCmix_test.go b/cmix/sendManyCmix_test.go
index 845dcd5981d49ca56112d1394041968cb8a3b0ee..a127154e56110a1ff1f78590102919d3e2a44277 100644
--- a/cmix/sendManyCmix_test.go
+++ b/cmix/sendManyCmix_test.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package cmix
 
 // func TestClient_SendMany_SendManyCMIX(t *testing.T) {
diff --git a/cmix/trackResults.go b/cmix/trackResults.go
index c27b259408fe814d9fc1218b0f49047bc3ad4564..412c38974f38991f05e7ee2d146a37d7ef4438e2 100644
--- a/cmix/trackResults.go
+++ b/cmix/trackResults.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package cmix
 
diff --git a/cmix/utils_test.go b/cmix/utils_test.go
index 9d7b20d3df65c8dd77b4e464ac1898e6c1eaae5d..0a0cb6d2264412e767de7840fc73f07230e0b2c6 100644
--- a/cmix/utils_test.go
+++ b/cmix/utils_test.go
@@ -1,12 +1,14 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package cmix
 
 import (
+	"gitlab.com/elixxir/client/cmix/rounds"
 	"time"
 
 	"github.com/pkg/errors"
@@ -191,14 +193,14 @@ func (mrr *mockRoundEventRegistrar) AddRoundEventChan(rid id.Round, eventChan ch
 
 // mockCriticalSender
 func mockCriticalSender(msg format.Message, recipient *id.ID,
-	params CMIXParams) (id.Round, ephemeral.Id, error) {
-	return id.Round(1), ephemeral.Id{}, nil
+	params CMIXParams) (rounds.Round, ephemeral.Id, error) {
+	return rounds.Round{ID: 1}, ephemeral.Id{}, nil
 }
 
 // mockFailCriticalSender
 func mockFailCriticalSender(msg format.Message, recipient *id.ID,
-	params CMIXParams) (id.Round, ephemeral.Id, error) {
-	return id.Round(1), ephemeral.Id{}, errors.New("Test error")
+	params CMIXParams) (rounds.Round, ephemeral.Id, error) {
+	return rounds.Round{ID: 1}, ephemeral.Id{}, errors.New("Test error")
 }
 
 // func newTestClient(t *testing.T) (*client, error) {
diff --git a/connect/authCallbacks.go b/connect/authCallbacks.go
index 4588557b0a58fbb89623d4a46f988b4c495d4362..ab1ff7b0a2138e7fbea34486425759dd37b28c1c 100644
--- a/connect/authCallbacks.go
+++ b/connect/authCallbacks.go
@@ -1,7 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2022 Privategrity Corporation                                   /
-//                                                                             /
-// All rights reserved.                                                        /
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package connect
diff --git a/connect/authenticated.go b/connect/authenticated.go
index 6a311978d78333ec9709151e7528c7da7f55657f..c5493deb0da13d227017e6695789f9317da2c830 100644
--- a/connect/authenticated.go
+++ b/connect/authenticated.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package connect
 
@@ -67,7 +67,7 @@ func ConnectWithAuthentication(recipient contact.Contact, user *xxdk.E2e,
 
 	// Build the authenticated connection and return
 	identity := user.GetReceptionIdentity()
-	privKey, err := identity.GetRSAPrivatePem()
+	privKey, err := identity.GetRSAPrivateKey()
 	if err != nil {
 		return nil, err
 	}
@@ -98,7 +98,7 @@ func connectWithAuthentication(conn Connection, timeStart time.Time,
 	}
 
 	// Send message to server
-	rids, _, _, err := conn.SendE2E(catalog.ConnectionAuthenticationRequest,
+	sendReport, err := conn.SendE2E(catalog.ConnectionAuthenticationRequest,
 		payload, clientE2e.GetDefaultParams())
 	if err != nil {
 		// Close connection on an error
@@ -138,12 +138,8 @@ func connectWithAuthentication(conn Connection, timeStart time.Time,
 
 	// Track the result of the round(s) we sent the
 	// identity authentication message on
-	err = net.GetRoundResults(remainingTime,
-		roundCb, rids...)
-	if err != nil {
-		return nil, errors.Errorf("could not track rounds for successful " +
-			"identity confirmation message delivery")
-	}
+	net.GetRoundResults(remainingTime,
+		roundCb, sendReport.RoundList...)
 	// Block waiting for confirmation of the round(s) success (or timeout
 	jww.DEBUG.Printf("AuthenticatedConnection waiting for authenticated "+
 		"connection with %s to be established...", recipient.ID.String())
diff --git a/connect/authenticated.pb.go b/connect/authenticated.pb.go
index a12961650fe8a763a5b07be50163f4b4ef496acc..f78d97c7c552b5e888f61a7cbe89aa4f908cb1f0 100644
--- a/connect/authenticated.pb.go
+++ b/connect/authenticated.pb.go
@@ -1,100 +1,174 @@
-// Code generated by protoc-gen-go. DO NOT EDIT.
-// source: connect/authenticated/authenticated.proto
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
-package connect // import "gitlab.com/elixxir/client/connect/authenticated"
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// 	protoc-gen-go v1.27.1
+// 	protoc        v3.15.6
+// source: authenticated.proto
 
-import proto "github.com/golang/protobuf/proto"
-import fmt "fmt"
-import math "math"
+package connect
 
-// Reference imports to suppress errors if they are not otherwise used.
-var _ = proto.Marshal
-var _ = fmt.Errorf
-var _ = math.Inf
+import (
+	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+	reflect "reflect"
+	sync "sync"
+)
 
-// This is a compile-time assertion to ensure that this generated file
-// is compatible with the proto package it is being compiled against.
-// A compilation error at this line likely means your copy of the
-// proto package needs to be updated.
-const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
+const (
+	// Verify that this generated code is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+	// Verify that runtime/protoimpl is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
 
 // Sent by the receiver of the authenticated connection request.
 type IdentityAuthentication struct {
-	Signature []byte `protobuf:"bytes,1,opt,name=Signature,proto3" json:"Signature,omitempty"`
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Signature []byte `protobuf:"bytes,1,opt,name=Signature,proto3" json:"Signature,omitempty"` // Signature of the connection fingerprint
 	// established between the two partners
-	RsaPubKey []byte `protobuf:"bytes,2,opt,name=RsaPubKey,proto3" json:"RsaPubKey,omitempty"`
+	RsaPubKey []byte `protobuf:"bytes,2,opt,name=RsaPubKey,proto3" json:"RsaPubKey,omitempty"` // The RSA public key of the sender of this message,
 	// PEM-encoded
-	Salt                 []byte   `protobuf:"bytes,3,opt,name=Salt,proto3" json:"Salt,omitempty"`
-	XXX_NoUnkeyedLiteral struct{} `json:"-"`
-	XXX_unrecognized     []byte   `json:"-"`
-	XXX_sizecache        int32    `json:"-"`
+	Salt []byte `protobuf:"bytes,3,opt,name=Salt,proto3" json:"Salt,omitempty"` // Salt used to generate the network ID of the client
 }
 
-func (m *IdentityAuthentication) Reset()         { *m = IdentityAuthentication{} }
-func (m *IdentityAuthentication) String() string { return proto.CompactTextString(m) }
-func (*IdentityAuthentication) ProtoMessage()    {}
-func (*IdentityAuthentication) Descriptor() ([]byte, []int) {
-	return fileDescriptor_authenticated_9ed9358e4abe7a3a, []int{0}
-}
-func (m *IdentityAuthentication) XXX_Unmarshal(b []byte) error {
-	return xxx_messageInfo_IdentityAuthentication.Unmarshal(m, b)
-}
-func (m *IdentityAuthentication) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
-	return xxx_messageInfo_IdentityAuthentication.Marshal(b, m, deterministic)
-}
-func (dst *IdentityAuthentication) XXX_Merge(src proto.Message) {
-	xxx_messageInfo_IdentityAuthentication.Merge(dst, src)
+func (x *IdentityAuthentication) Reset() {
+	*x = IdentityAuthentication{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_authenticated_proto_msgTypes[0]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
 }
-func (m *IdentityAuthentication) XXX_Size() int {
-	return xxx_messageInfo_IdentityAuthentication.Size(m)
+
+func (x *IdentityAuthentication) String() string {
+	return protoimpl.X.MessageStringOf(x)
 }
-func (m *IdentityAuthentication) XXX_DiscardUnknown() {
-	xxx_messageInfo_IdentityAuthentication.DiscardUnknown(m)
+
+func (*IdentityAuthentication) ProtoMessage() {}
+
+func (x *IdentityAuthentication) ProtoReflect() protoreflect.Message {
+	mi := &file_authenticated_proto_msgTypes[0]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
 }
 
-var xxx_messageInfo_IdentityAuthentication proto.InternalMessageInfo
+// Deprecated: Use IdentityAuthentication.ProtoReflect.Descriptor instead.
+func (*IdentityAuthentication) Descriptor() ([]byte, []int) {
+	return file_authenticated_proto_rawDescGZIP(), []int{0}
+}
 
-func (m *IdentityAuthentication) GetSignature() []byte {
-	if m != nil {
-		return m.Signature
+func (x *IdentityAuthentication) GetSignature() []byte {
+	if x != nil {
+		return x.Signature
 	}
 	return nil
 }
 
-func (m *IdentityAuthentication) GetRsaPubKey() []byte {
-	if m != nil {
-		return m.RsaPubKey
+func (x *IdentityAuthentication) GetRsaPubKey() []byte {
+	if x != nil {
+		return x.RsaPubKey
 	}
 	return nil
 }
 
-func (m *IdentityAuthentication) GetSalt() []byte {
-	if m != nil {
-		return m.Salt
+func (x *IdentityAuthentication) GetSalt() []byte {
+	if x != nil {
+		return x.Salt
 	}
 	return nil
 }
 
-func init() {
-	proto.RegisterType((*IdentityAuthentication)(nil), "authenticatedConnectionMessages.IdentityAuthentication")
+var File_authenticated_proto protoreflect.FileDescriptor
+
+var file_authenticated_proto_rawDesc = []byte{
+	0x0a, 0x13, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x2e,
+	0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x07, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x22, 0x68,
+	0x0a, 0x16, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e,
+	0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1c, 0x0a, 0x09, 0x53, 0x69, 0x67, 0x6e,
+	0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x53, 0x69, 0x67,
+	0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x52, 0x73, 0x61, 0x50, 0x75, 0x62,
+	0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x52, 0x73, 0x61, 0x50, 0x75,
+	0x62, 0x4b, 0x65, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x53, 0x61, 0x6c, 0x74, 0x18, 0x03, 0x20, 0x01,
+	0x28, 0x0c, 0x52, 0x04, 0x53, 0x61, 0x6c, 0x74, 0x42, 0x23, 0x5a, 0x21, 0x67, 0x69, 0x74, 0x6c,
+	0x61, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x65, 0x6c, 0x69, 0x78, 0x78, 0x69, 0x72, 0x2f, 0x63,
+	0x6c, 0x69, 0x65, 0x6e, 0x74, 0x2f, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x62, 0x06, 0x70,
+	0x72, 0x6f, 0x74, 0x6f, 0x33,
+}
+
+var (
+	file_authenticated_proto_rawDescOnce sync.Once
+	file_authenticated_proto_rawDescData = file_authenticated_proto_rawDesc
+)
+
+func file_authenticated_proto_rawDescGZIP() []byte {
+	file_authenticated_proto_rawDescOnce.Do(func() {
+		file_authenticated_proto_rawDescData = protoimpl.X.CompressGZIP(file_authenticated_proto_rawDescData)
+	})
+	return file_authenticated_proto_rawDescData
 }
 
-func init() {
-	proto.RegisterFile("connect/authenticated/authenticated.proto", fileDescriptor_authenticated_9ed9358e4abe7a3a)
+var file_authenticated_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
+var file_authenticated_proto_goTypes = []interface{}{
+	(*IdentityAuthentication)(nil), // 0: connect.IdentityAuthentication
+}
+var file_authenticated_proto_depIdxs = []int32{
+	0, // [0:0] is the sub-list for method output_type
+	0, // [0:0] is the sub-list for method input_type
+	0, // [0:0] is the sub-list for extension type_name
+	0, // [0:0] is the sub-list for extension extendee
+	0, // [0:0] is the sub-list for field type_name
 }
 
-var fileDescriptor_authenticated_9ed9358e4abe7a3a = []byte{
-	// 180 bytes of a gzipped FileDescriptorProto
-	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xd2, 0x4d, 0xce, 0xcf, 0xcb,
-	0x4b, 0x4d, 0x2e, 0xc9, 0xcc, 0xcf, 0x2b, 0xd6, 0x4f, 0x2c, 0x2d, 0xc9, 0x48, 0xcd, 0x2b, 0xc9,
-	0x4c, 0x4e, 0x2c, 0x49, 0x4d, 0x41, 0xe5, 0xe9, 0x15, 0x14, 0xe5, 0x97, 0xe4, 0x0b, 0xc9, 0xa3,
-	0x08, 0x3a, 0xc3, 0xf5, 0xfa, 0xa6, 0x16, 0x17, 0x27, 0xa6, 0xa7, 0x16, 0x2b, 0x65, 0x70, 0x89,
-	0x79, 0xa6, 0x80, 0x14, 0x94, 0x54, 0x3a, 0x22, 0x94, 0x66, 0xe6, 0xe7, 0x09, 0xc9, 0x70, 0x71,
-	0x06, 0x67, 0xa6, 0xe7, 0x25, 0x96, 0x94, 0x16, 0xa5, 0x4a, 0x30, 0x2a, 0x30, 0x6a, 0xf0, 0x04,
-	0x21, 0x04, 0x40, 0xb2, 0x41, 0xc5, 0x89, 0x01, 0xa5, 0x49, 0xde, 0xa9, 0x95, 0x12, 0x4c, 0x10,
-	0x59, 0xb8, 0x80, 0x90, 0x10, 0x17, 0x4b, 0x70, 0x62, 0x4e, 0x89, 0x04, 0x33, 0x58, 0x02, 0xcc,
-	0x76, 0x32, 0x8d, 0x32, 0x4e, 0xcf, 0x2c, 0xc9, 0x49, 0x4c, 0xd2, 0x4b, 0xce, 0xcf, 0xd5, 0x4f,
-	0xcd, 0xc9, 0xac, 0xa8, 0xc8, 0x2c, 0xd2, 0x4f, 0xce, 0xc9, 0x4c, 0xcd, 0x2b, 0xd1, 0xc7, 0xe9,
-	0xab, 0x24, 0x36, 0xb0, 0x47, 0x8c, 0x01, 0x01, 0x00, 0x00, 0xff, 0xff, 0x71, 0x89, 0x27, 0xcf,
-	0xf9, 0x00, 0x00, 0x00,
+func init() { file_authenticated_proto_init() }
+func file_authenticated_proto_init() {
+	if File_authenticated_proto != nil {
+		return
+	}
+	if !protoimpl.UnsafeEnabled {
+		file_authenticated_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*IdentityAuthentication); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+	}
+	type x struct{}
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+			RawDescriptor: file_authenticated_proto_rawDesc,
+			NumEnums:      0,
+			NumMessages:   1,
+			NumExtensions: 0,
+			NumServices:   0,
+		},
+		GoTypes:           file_authenticated_proto_goTypes,
+		DependencyIndexes: file_authenticated_proto_depIdxs,
+		MessageInfos:      file_authenticated_proto_msgTypes,
+	}.Build()
+	File_authenticated_proto = out.File
+	file_authenticated_proto_rawDesc = nil
+	file_authenticated_proto_goTypes = nil
+	file_authenticated_proto_depIdxs = nil
 }
diff --git a/connect/authenticated.proto b/connect/authenticated.proto
index 926ca845e35c6a25e91ff4b1d4f477c2eaea5c2d..4a8e8c87b6b8c33cf684d8e8f4c810690e07d643 100644
--- a/connect/authenticated.proto
+++ b/connect/authenticated.proto
@@ -1,21 +1,24 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 syntax = "proto3";
-package authenticatedConnectionMessages;
-option go_package = "gitlab.com/elixxir/client/connect/authenticated";
+
+package connect;
+
+option go_package = "gitlab.com/elixxir/client/connect";
+
 
 // Sent by the receiver of the authenticated connection request.
 message IdentityAuthentication {
-  bytes Signature      = 1;  // Signature of the connection fingerprint
-        // established between the two partners
-  bytes RsaPubKey = 2; // The RSA public key of the sender of this message,
-        // PEM-encoded
-  bytes Salt = 3; // Salt used to generate the network ID of the client
+    bytes Signature = 1;  // Signature of the connection fingerprint
+                          // established between the two partners
+    bytes RsaPubKey = 2;  // The RSA public key of the sender of this message,
+                          // PEM-encoded
+    bytes Salt = 3;       // Salt used to generate the network ID of the client
 }
 
 
diff --git a/connect/authenticated_test.go b/connect/authenticated_test.go
index d4f5be3d2875ff0841ce91a6f81c4f5ef846c204..2a40522904027498015e3e56eec9d8deebb30e35 100644
--- a/connect/authenticated_test.go
+++ b/connect/authenticated_test.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package connect
 
diff --git a/connect/client.go b/connect/client.go
index 809c5da3017ba707dd9037ce624ae1045f3f252f..3c335f3d02398c2b118d00b43fde388b4bd936c1 100644
--- a/connect/client.go
+++ b/connect/client.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package connect
 
diff --git a/connect/compileProtobuf.sh b/connect/compileProtobuf.sh
new file mode 100644
index 0000000000000000000000000000000000000000..e29b74cf9c8b8e989146d728f9c4a07d4a76d745
--- /dev/null
+++ b/connect/compileProtobuf.sh
@@ -0,0 +1,14 @@
+#!/bin/bash
+################################################################################
+## Copyright © 2022 xx foundation                                             ##
+##                                                                            ##
+## Use of this source code is governed by a license that can be found in the  ##
+## LICENSE file.                                                              ##
+################################################################################
+
+# This script will compile the Protobuf file to a Go file (pb.go).
+# This is meant to be called from the top level of the repo.
+
+cd ./connect/ || return
+
+protoc --go_out=. --go_opt=paths=source_relative ./authenticated.proto
diff --git a/connect/connect.go b/connect/connect.go
index ba87dc91873e5d3153e38c60474d42b2f3e23cbc..d786676958b11edc0dd4137e492039c8fa37707e 100644
--- a/connect/connect.go
+++ b/connect/connect.go
@@ -1,12 +1,14 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2022 Privategrity Corporation                                   /
-//                                                                             /
-// All rights reserved.                                                        /
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package connect
 
 import (
+	cryptoE2e "gitlab.com/elixxir/crypto/e2e"
 	"io"
 	"sync/atomic"
 	"time"
@@ -22,8 +24,6 @@ import (
 	"gitlab.com/elixxir/client/e2e/ratchet/partner"
 	"gitlab.com/elixxir/client/e2e/receive"
 	"gitlab.com/elixxir/crypto/contact"
-	"gitlab.com/elixxir/crypto/e2e"
-	"gitlab.com/xx_network/primitives/id"
 )
 
 var alreadyClosedErr = errors.New("connection is closed")
@@ -43,7 +43,7 @@ type Connection interface {
 	// SendE2E is a wrapper for sending specifically to the Connection's
 	// partner.Manager
 	SendE2E(mt catalog.MessageType, payload []byte, params clientE2e.Params) (
-		[]id.Round, e2e.MessageID, time.Time, error)
+		cryptoE2e.SendReport, error)
 
 	// RegisterListener is used for E2E reception
 	// and allows for reading data sent from the partner.Manager
@@ -221,9 +221,9 @@ func (h *handler) GetPartner() partner.Manager {
 // SendE2E is a wrapper for sending specifically to the Connection's
 // partner.Manager.
 func (h *handler) SendE2E(mt catalog.MessageType, payload []byte,
-	params clientE2e.Params) ([]id.Round, e2e.MessageID, time.Time, error) {
+	params clientE2e.Params) (cryptoE2e.SendReport, error) {
 	if h.isClosed() {
-		return nil, e2e.MessageID{}, time.Time{}, alreadyClosedErr
+		return cryptoE2e.SendReport{}, alreadyClosedErr
 	}
 
 	h.updateLastUse(netTime.Now())
diff --git a/connect/connectionList.go b/connect/connectionList.go
index fab3404126334ce4c3e0b29f46f9e307a751894e..4d35bd2338f5742961f37c6883de9050feb619c4 100644
--- a/connect/connectionList.go
+++ b/connect/connectionList.go
@@ -1,8 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package connect
diff --git a/connect/connectionList_test.go b/connect/connectionList_test.go
index b76c6b35876ee6656b099a46b663a75820db08e5..5a97e78c4509565e4d6e50ce21d732bc0875bddc 100644
--- a/connect/connectionList_test.go
+++ b/connect/connectionList_test.go
@@ -1,8 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package connect
diff --git a/connect/crypto.go b/connect/crypto.go
index 391aa1b2778dd936754182f78f57e5fa80854f39..61714203fb05c659a65ee2517196cc4f583dc080 100644
--- a/connect/crypto.go
+++ b/connect/crypto.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package connect
 
 import (
diff --git a/connect/crypto_test.go b/connect/crypto_test.go
index 633e47a700e98034df89df6f51192a4c6117a790..0d3c163757257a038e309adb4a0e13b8b6aa183f 100644
--- a/connect/crypto_test.go
+++ b/connect/crypto_test.go
@@ -1,8 +1,9 @@
-////////////////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2022 xx network SEZC                                                       //
-//                                                                                        //
-// Use of this source code is governed by a license that can be found in the LICENSE file //
-////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package connect
 
diff --git a/connect/generateProto.sh b/connect/generateProto.sh
deleted file mode 100755
index b27e351d7d0c5784e9564cfc2b1e6b2ba7889aa6..0000000000000000000000000000000000000000
--- a/connect/generateProto.sh
+++ /dev/null
@@ -1,6 +0,0 @@
-#!/bin/bash
-
-# This script will generate the protobuf Golang file (pb.go) out of the protobuf file (.proto).
-# This is meant to be called from the top level of the repo.
-
-protoc --go_out=paths=source_relative:. connections/authenticated/authenticated.proto
diff --git a/connect/listenerTracker.go b/connect/listenerTracker.go
index 875598dfe53d314cf0052c2ab592ceff425b032c..07f926ba591f0cbe0c384cdf865754d479a09976 100644
--- a/connect/listenerTracker.go
+++ b/connect/listenerTracker.go
@@ -1,8 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package connect
diff --git a/connect/listenerTracker_test.go b/connect/listenerTracker_test.go
index 1cab220ad7955c6b25be5b716fc41197eefc055b..f0c69253464c469e8a760b42c71c044f70c07f1b 100644
--- a/connect/listenerTracker_test.go
+++ b/connect/listenerTracker_test.go
@@ -1,8 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package connect
diff --git a/connect/params_test.go b/connect/params_test.go
index 98bb5e2953b5ec570639c0601e78924b7e39c6ec..6d84c7699cd5389850b6725da85fafd49ad6ea77 100644
--- a/connect/params_test.go
+++ b/connect/params_test.go
@@ -1,8 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package connect
diff --git a/connect/server.go b/connect/server.go
index b9f77b28b05b5f9af692fce2f532808a82b02e99..96eb01294a6afb75516bad22026186c933ecdb9c 100644
--- a/connect/server.go
+++ b/connect/server.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package connect
 
diff --git a/connect/utils_test.go b/connect/utils_test.go
index 6e4be5173d00cd8ba4b671d6abee3a8669e1c77c..86f190808b95d44e80cff854d87be643339f2f0c 100644
--- a/connect/utils_test.go
+++ b/connect/utils_test.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package connect
 
 import (
@@ -115,8 +122,7 @@ func (m *mockConnection) Close() error {
 func (m *mockConnection) GetPartner() partner.Manager { return m.partner }
 
 func (m *mockConnection) SendE2E(
-	mt catalog.MessageType, payload []byte, _ e2e.Params) (
-	[]id.Round, cryptoE2e.MessageID, time.Time, error) {
+	mt catalog.MessageType, payload []byte, _ e2e.Params) (cryptoE2e.SendReport, error) {
 	m.payloadChan <- payload
 	m.listener.Hear(receive.Message{
 		MessageType: mt,
@@ -124,7 +130,7 @@ func (m *mockConnection) SendE2E(
 		Sender:      m.partner.myID,
 		RecipientID: m.partner.partnerId,
 	})
-	return nil, cryptoE2e.MessageID{}, time.Time{}, nil
+	return cryptoE2e.SendReport{}, nil
 }
 
 func (m *mockConnection) RegisterListener(
@@ -154,11 +160,17 @@ func (m *mockCmix) Follow(cmix.ClientErrorReport) (stoppable.Stoppable, error) {
 func (m *mockCmix) GetMaxMessageLength() int { return 4096 }
 
 func (m *mockCmix) Send(*id.ID, format.Fingerprint, message.Service, []byte,
-	[]byte, cmix.CMIXParams) (id.Round, ephemeral.Id, error) {
-	return 0, ephemeral.Id{}, nil
+	[]byte, cmix.CMIXParams) (rounds.Round, ephemeral.Id, error) {
+	return rounds.Round{}, ephemeral.Id{}, nil
 }
-func (m *mockCmix) SendMany([]cmix.TargetedCmixMessage, cmix.CMIXParams) (id.Round, []ephemeral.Id, error) {
-	return 0, []ephemeral.Id{}, nil
+
+func (m *mockCmix) SendWithAssembler(recipient *id.ID, assembler cmix.MessageAssembler,
+	cmixParams cmix.CMIXParams) (rounds.Round, ephemeral.Id, error) {
+	return rounds.Round{}, ephemeral.Id{}, nil
+}
+
+func (m *mockCmix) SendMany([]cmix.TargetedCmixMessage, cmix.CMIXParams) (rounds.Round, []ephemeral.Id, error) {
+	return rounds.Round{}, []ephemeral.Id{}, nil
 }
 func (m *mockCmix) AddIdentity(*id.ID, time.Time, bool) {}
 func (m *mockCmix) RemoveIdentity(*id.ID)               {}
@@ -183,9 +195,8 @@ func (m *mockCmix) HasNode(*id.ID) bool
 func (m *mockCmix) NumRegisteredNodes() int                                            { return 24 }
 func (m *mockCmix) TriggerNodeRegistration(*id.ID)                                     {}
 
-func (m *mockCmix) GetRoundResults(_ time.Duration, roundCallback cmix.RoundEventCallback, _ ...id.Round) error {
+func (m *mockCmix) GetRoundResults(_ time.Duration, roundCallback cmix.RoundEventCallback, _ ...id.Round) {
 	roundCallback(true, false, nil)
-	return nil
 }
 
 func (m *mockCmix) LookupHistoricalRound(id.Round, rounds.RoundResultCallback) error { return nil }
diff --git a/dummy/manager.go b/dummy/manager.go
index 4832f3ef505ea37114c2f4d202c82604ddd7eab0..83feb81d324b560dc3850469f0a1acc2c852e52c 100644
--- a/dummy/manager.go
+++ b/dummy/manager.go
@@ -1,8 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 // Package dummy allows for the sending of dummy messages to dummy recipients
@@ -12,7 +12,7 @@ package dummy
 
 import (
 	"github.com/pkg/errors"
-	"gitlab.com/elixxir/client/interfaces"
+	"gitlab.com/elixxir/client/cmix"
 	"gitlab.com/elixxir/client/stoppable"
 	"gitlab.com/elixxir/client/storage"
 	"gitlab.com/elixxir/client/xxdk"
@@ -21,20 +21,25 @@ import (
 	"time"
 )
 
+// Manager related thread handling constants.
 const (
+	// The name of the Manager's stoppable.Stoppable
 	dummyTrafficStoppableName = "DummyTraffic"
-	statusChanLen             = 100
+
+	// The amount of statuses in queue that can be placed
+	// by Manager.SetStatus.
+	statusChanLen = 100
 )
 
-// Thread status.
+// The thread status values.
 const (
-	notStarted uint32 = iota
-	running
-	paused
-	stopped
+	notStarted uint32 = iota // Sending thread has not been started
+	running                  // Sending thread is currently operating
+	paused                   // Sending thread is temporarily halted.
+	stopped                  // Sending thread is halted.
 )
 
-// Error messages.
+// Error messages for Manager.
 const (
 	setStatusErr = "Failed to change status of dummy traffic send thread to %t: channel full"
 )
@@ -56,27 +61,41 @@ type Manager struct {
 	// Pauses/Resumes the dummy send thread when triggered
 	statusChan chan bool
 
-	// Cmix interfaces
-	net            *xxdk.Cmix
-	store          *storage.Session
-	networkManager interfaces.NetworkManager
-	rng            *fastRNG.StreamGenerator
+	// Interfaces
+	net   cmix.Client
+	store storage.Session
+
+	// Generates
+	rng *fastRNG.StreamGenerator
 }
 
-// NewManager creates a new dummy Manager with the specified average send delta
-// and the range used for generating random durations.
-func NewManager(maxNumMessages int, avgSendDelta, randomRange time.Duration,
-	net *xxdk.Cmix, manager interfaces.NetworkManager) *Manager {
-	clientStorage := net.GetStorage()
-	return newManager(maxNumMessages, avgSendDelta, randomRange, net,
-		&clientStorage, manager, net.GetRng())
+// NewManager creates a Manager object and initialises the
+// dummy traffic sending thread. Note that the Manager does not start sending dummy
+// traffic until `True` is passed into Manager.SetStatus. The time duration
+// between each sending operation and the amount of messages sent each interval
+// are randomly generated values with bounds defined by the
+// given parameters below.
+//
+// Params:
+//  - maxNumMessages - the upper bound of the random number of messages sent
+//    each sending cycle.
+//  - avgSendDeltaMS - the average duration, in milliseconds, to wait
+//    between sends.
+//  - randomRangeMS - the upper bound of the interval between sending cycles,
+//    in milliseconds. Sends occur every avgSendDeltaMS +/- a random duration
+//    with an upper bound of randomRangeMS.
+func NewManager(maxNumMessages int,
+	avgSendDelta, randomRange time.Duration,
+	net *xxdk.Cmix) *Manager {
+
+	return newManager(maxNumMessages, avgSendDelta, randomRange, net.GetCmix(),
+		net.GetStorage(), net.GetRng())
 }
 
 // newManager builds a new dummy Manager from fields explicitly passed in. This
-// function is a helper function for NewManager to make it easier to test.
+// function is a helper function for NewManager.
 func newManager(maxNumMessages int, avgSendDelta, randomRange time.Duration,
-	net *xxdk.Cmix, store *storage.Session, networkManager interfaces.NetworkManager,
-	rng *fastRNG.StreamGenerator) *Manager {
+	net cmix.Client, store storage.Session, rng *fastRNG.StreamGenerator) *Manager {
 	return &Manager{
 		maxNumMessages: maxNumMessages,
 		avgSendDelta:   avgSendDelta,
@@ -85,13 +104,12 @@ func newManager(maxNumMessages int, avgSendDelta, randomRange time.Duration,
 		statusChan:     make(chan bool, statusChanLen),
 		net:            net,
 		store:          store,
-		networkManager: networkManager,
 		rng:            rng,
 	}
 }
 
 // StartDummyTraffic starts the process of sending dummy traffic. This function
-// matches the xxdk.Service type.
+// adheres to xxdk.Service.
 func (m *Manager) StartDummyTraffic() (stoppable.Stoppable, error) {
 	stop := stoppable.NewSingle(dummyTrafficStoppableName)
 	go m.sendThread(stop)
@@ -99,13 +117,19 @@ func (m *Manager) StartDummyTraffic() (stoppable.Stoppable, error) {
 	return stop, nil
 }
 
-// SetStatus sets the state of the dummy traffic send thread, which determines
-// if the thread is running or paused. The possible statuses are:
-//  true  = send thread is sending dummy messages
-//  false = send thread is paused/stopped and not sending dummy messages
-// Returns an error if the channel is full.
-// Note that this function cannot change the status of the send thread if it has
-// yet to be started via StartDummyTraffic or if it has been stopped.
+// SetStatus sets the state of the dummy traffic send thread by passing in
+// a boolean parameter. There may be a small delay in between this call
+// and the status of the sending thread to change accordingly. For example,
+// passing False into this call while the sending thread is currently sending messages
+// will not cancel nor halt the sending operation, but will pause the thread once that
+// operation has completed.
+//
+// Params:
+//  - boolean - Input should be true if you want to send dummy messages.
+//  			Input should be false if you want to pause dummy messages.
+// Returns:
+//  - error - if the Manager.SetStatus is called too frequently, causing the
+//    internal status channel to fill.
 func (m *Manager) SetStatus(status bool) error {
 	select {
 	case m.statusChan <- status:
@@ -115,13 +139,16 @@ func (m *Manager) SetStatus(status bool) error {
 	}
 }
 
-// GetStatus returns the current state of the dummy traffic send thread. It has
-// the following return values:
-//  true  = send thread is sending dummy messages
-//  false = send thread is paused/stopped and not sending dummy messages
-// Note that this function does not return the status set by SetStatus directly;
-// it returns the current status of the send thread, which means any call to
-// SetStatus will have a small delay before it is returned by GetStatus.
+// GetStatus returns the current state of the Manager's sending thread.
+// Note that this function does not return the status set by the most recent call to
+// SetStatus. Instead, this call returns the current status of the sending thread.
+// This is due to the small delay that may occur between calling SetStatus and the
+// sending thread taking into effect that status change.
+//
+// Returns:
+//   - boolean - Returns true if sending thread is sending dummy messages.
+//  	         Returns false if sending thread is paused/stopped and is
+// 	             not sending dummy messages.
 func (m *Manager) GetStatus() bool {
 	switch atomic.LoadUint32(&m.status) {
 	case running:
diff --git a/dummy/manager_test.go b/dummy/manager_test.go
index 6a49bcc6a597ebf476ee8bbfb8f45a79045a4488..c36b2a596292f35104e69be797ef999f3f3ada3e 100644
--- a/dummy/manager_test.go
+++ b/dummy/manager_test.go
@@ -1,8 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package dummy
@@ -27,7 +27,7 @@ func Test_newManager(t *testing.T) {
 	}
 
 	received := newManager(expected.maxNumMessages, expected.avgSendDelta,
-		expected.randomRange, nil, nil, nil, nil)
+		expected.randomRange, nil, nil, nil)
 
 	if statusChanLen != cap(received.statusChan) {
 		t.Errorf("Capacity of status channel unexpected."+
@@ -45,7 +45,7 @@ func Test_newManager(t *testing.T) {
 // Tests that Manager.StartDummyTraffic sends dummy messages and that it stops
 // when the stoppable is closed.
 func TestManager_StartDummyTraffic(t *testing.T) {
-	m := newTestManager(10, 50*time.Millisecond, 10*time.Millisecond, false, t)
+	m := newTestManager(10, 50*time.Millisecond, 10*time.Millisecond, t)
 
 	err := m.SetStatus(true)
 	if err != nil {
@@ -59,7 +59,7 @@ func TestManager_StartDummyTraffic(t *testing.T) {
 
 	msgChan := make(chan bool)
 	go func() {
-		for m.networkManager.(*testNetworkManager).GetMsgListLen() == 0 {
+		for m.net.(*mockCmix).GetMsgListLen() == 0 {
 			time.Sleep(5 * time.Millisecond)
 		}
 		msgChan <- true
@@ -71,7 +71,7 @@ func TestManager_StartDummyTraffic(t *testing.T) {
 		t.Errorf("Timed out after %s waiting for messages to be sent.",
 			3*m.avgSendDelta)
 	case <-msgChan:
-		numReceived += m.networkManager.(*testNetworkManager).GetMsgListLen()
+		numReceived += m.net.(*mockCmix).GetMsgListLen()
 	}
 
 	err = stop.Close()
@@ -86,7 +86,7 @@ func TestManager_StartDummyTraffic(t *testing.T) {
 
 	msgChan = make(chan bool)
 	go func() {
-		for m.networkManager.(*testNetworkManager).GetMsgListLen() == numReceived {
+		for m.net.(*mockCmix).GetMsgListLen() == numReceived {
 			time.Sleep(5 * time.Millisecond)
 		}
 		msgChan <- true
@@ -104,7 +104,7 @@ func TestManager_StartDummyTraffic(t *testing.T) {
 // can be called multiple times with the same status without it affecting
 // anything. Also tests that the thread quits even when paused.
 func TestManager_SetStatus(t *testing.T) {
-	m := newTestManager(10, 50*time.Millisecond, 10*time.Millisecond, false, t)
+	m := newTestManager(10, 50*time.Millisecond, 10*time.Millisecond, t)
 
 	err := m.SetStatus(false)
 	if err != nil {
@@ -118,10 +118,10 @@ func TestManager_SetStatus(t *testing.T) {
 	go func() {
 		var numReceived int
 		for i := 0; i < 2; i++ {
-			for m.networkManager.(*testNetworkManager).GetMsgListLen() == numReceived {
+			for m.net.(*mockCmix).GetMsgListLen() == numReceived {
 				time.Sleep(5 * time.Millisecond)
 			}
-			numReceived = m.networkManager.(*testNetworkManager).GetMsgListLen()
+			numReceived = m.net.(*mockCmix).GetMsgListLen()
 			msgChan <- true
 		}
 	}()
@@ -161,7 +161,7 @@ func TestManager_SetStatus(t *testing.T) {
 		t.Errorf("Timed out after %s waiting for messages to be sent.",
 			3*m.avgSendDelta)
 	case <-msgChan:
-		numReceived += m.networkManager.(*testNetworkManager).GetMsgListLen()
+		numReceived += m.net.(*mockCmix).GetMsgListLen()
 	}
 
 	// Setting status to true multiple times does not interrupt sending
@@ -177,10 +177,10 @@ func TestManager_SetStatus(t *testing.T) {
 		t.Errorf("Timed out after %s waiting for messages to be sent.",
 			3*m.avgSendDelta)
 	case <-msgChan:
-		if m.networkManager.(*testNetworkManager).GetMsgListLen() <= numReceived {
+		if m.net.(*mockCmix).GetMsgListLen() <= numReceived {
 			t.Errorf("Failed to receive second send."+
 				"\nmessages on last receive: %d\nmessages on this receive: %d",
-				numReceived, m.networkManager.(*testNetworkManager).GetMsgListLen())
+				numReceived, m.net.(*mockCmix).GetMsgListLen())
 		}
 	}
 
@@ -213,7 +213,7 @@ func TestManager_SetStatus(t *testing.T) {
 // Error path: tests that Manager.SetStatus returns an error if the status
 // cannot be set.
 func TestManager_SetStatus_ChannelError(t *testing.T) {
-	m := newTestManager(10, 50*time.Millisecond, 10*time.Millisecond, false, t)
+	m := newTestManager(10, 50*time.Millisecond, 10*time.Millisecond, t)
 
 	// Send the max number of status changes on the channel
 	for i := 0; i < statusChanLen; i++ {
@@ -236,7 +236,7 @@ func TestManager_SetStatus_ChannelError(t *testing.T) {
 // Tests that Manager.GetStatus gets the correct status before the send thread
 // starts, while sending, while paused, and after it is stopped.
 func TestManager_GetStatus(t *testing.T) {
-	m := newTestManager(10, 50*time.Millisecond, 10*time.Millisecond, false, t)
+	m := newTestManager(10, 50*time.Millisecond, 10*time.Millisecond, t)
 
 	err := m.SetStatus(false)
 	if err != nil {
@@ -254,10 +254,10 @@ func TestManager_GetStatus(t *testing.T) {
 	go func() {
 		var numReceived int
 		for i := 0; i < 2; i++ {
-			for m.networkManager.(*testNetworkManager).GetMsgListLen() == numReceived {
+			for m.net.(*mockCmix).GetMsgListLen() == numReceived {
 				time.Sleep(5 * time.Millisecond)
 			}
-			numReceived = m.networkManager.(*testNetworkManager).GetMsgListLen()
+			numReceived = m.net.(*mockCmix).GetMsgListLen()
 			msgChan <- true
 		}
 	}()
@@ -292,7 +292,7 @@ func TestManager_GetStatus(t *testing.T) {
 		t.Errorf("Timed out after %s waiting for messages to be sent.",
 			3*m.avgSendDelta)
 	case <-msgChan:
-		numReceived += m.networkManager.(*testNetworkManager).GetMsgListLen()
+		numReceived += m.net.(*mockCmix).GetMsgListLen()
 	}
 
 	// Setting status to true multiple times does not interrupt sending
@@ -311,10 +311,10 @@ func TestManager_GetStatus(t *testing.T) {
 		t.Errorf("Timed out after %s waiting for messages to be sent.",
 			3*m.avgSendDelta)
 	case <-msgChan:
-		if m.networkManager.(*testNetworkManager).GetMsgListLen() <= numReceived {
+		if m.net.(*mockCmix).GetMsgListLen() <= numReceived {
 			t.Errorf("Failed to receive second send."+
 				"\nmessages on last receive: %d\nmessages on this receive: %d",
-				numReceived, m.networkManager.(*testNetworkManager).GetMsgListLen())
+				numReceived, m.net.(*mockCmix).GetMsgListLen())
 		}
 	}
 
diff --git a/dummy/mockCmix_test.go b/dummy/mockCmix_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..96bab83384e0d57d84d50c5cac95ce71bc9fb7df
--- /dev/null
+++ b/dummy/mockCmix_test.go
@@ -0,0 +1,233 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
+package dummy
+
+import (
+	"gitlab.com/elixxir/client/cmix"
+	"gitlab.com/elixxir/client/cmix/gateway"
+	"gitlab.com/elixxir/client/cmix/identity"
+	"gitlab.com/elixxir/client/cmix/message"
+	"gitlab.com/elixxir/client/cmix/rounds"
+	"gitlab.com/elixxir/client/stoppable"
+	"gitlab.com/elixxir/comms/network"
+	"gitlab.com/elixxir/primitives/format"
+	"gitlab.com/xx_network/comms/connect"
+	"gitlab.com/xx_network/primitives/id"
+	"gitlab.com/xx_network/primitives/id/ephemeral"
+	"sync"
+	"time"
+)
+
+// mockCmix is a testing structure that adheres to cmix.Client.
+type mockCmix struct {
+	messages map[id.ID]format.Message
+	sync.RWMutex
+	payloadSize int
+}
+
+func newMockCmix(payloadSize int) cmix.Client {
+
+	return &mockCmix{
+		messages:    make(map[id.ID]format.Message),
+		payloadSize: payloadSize,
+	}
+}
+
+func (m *mockCmix) Send(recipient *id.ID, fingerprint format.Fingerprint, service message.Service, payload, mac []byte, cmixParams cmix.CMIXParams) (rounds.Round, ephemeral.Id, error) {
+	m.Lock()
+	defer m.Unlock()
+	m.messages[*recipient] = generateMessage(m.payloadSize, fingerprint, service, payload, mac)
+
+	return rounds.Round{}, ephemeral.Id{}, nil
+}
+
+func (m *mockCmix) SendWithAssembler(recipient *id.ID, assembler cmix.MessageAssembler,
+	cmixParams cmix.CMIXParams) (rounds.Round, ephemeral.Id, error) {
+	m.Lock()
+	defer m.Unlock()
+
+	fingerprint, service, payload, mac, err := assembler(42)
+	if err != nil {
+		return rounds.Round{}, ephemeral.Id{}, err
+	}
+	m.messages[*recipient] = generateMessage(m.payloadSize, fingerprint, service, payload, mac)
+
+	return rounds.Round{}, ephemeral.Id{}, nil
+}
+
+func (m *mockCmix) GetMsgListLen() int {
+	m.RLock()
+	defer m.RUnlock()
+	return len(m.messages)
+}
+
+func (m *mockCmix) GetMsgList() map[id.ID]format.Message {
+	m.RLock()
+	defer m.RUnlock()
+	return m.messages
+}
+
+func (m mockCmix) Follow(report cmix.ClientErrorReport) (stoppable.Stoppable, error) {
+	//TODO implement me
+	panic("implement me")
+}
+
+func (m mockCmix) GetMaxMessageLength() int {
+	//TODO implement me
+	panic("implement me")
+}
+
+func (m *mockCmix) SendMany(messages []cmix.TargetedCmixMessage, p cmix.CMIXParams) (rounds.Round, []ephemeral.Id, error) {
+	//TODO implement me
+	panic("implement me")
+}
+
+func (m *mockCmix) AddIdentity(id *id.ID, validUntil time.Time, persistent bool) {
+	//TODO implement me
+	panic("implement me")
+}
+
+func (m *mockCmix) RemoveIdentity(id *id.ID) {
+	//TODO implement me
+	panic("implement me")
+}
+
+func (m mockCmix) GetIdentity(get *id.ID) (identity.TrackedID, error) {
+	//TODO implement me
+	panic("implement me")
+}
+
+func (m mockCmix) AddFingerprint(identity *id.ID, fingerprint format.Fingerprint, mp message.Processor) error {
+	//TODO implement me
+	panic("implement me")
+}
+
+func (m mockCmix) DeleteFingerprint(identity *id.ID, fingerprint format.Fingerprint) {
+	//TODO implement me
+	panic("implement me")
+}
+
+func (m mockCmix) DeleteClientFingerprints(identity *id.ID) {
+	//TODO implement me
+	panic("implement me")
+}
+
+func (m mockCmix) AddService(clientID *id.ID, newService message.Service, response message.Processor) {
+	//TODO implement me
+	panic("implement me")
+}
+
+func (m mockCmix) DeleteService(clientID *id.ID, toDelete message.Service, processor message.Processor) {
+	//TODO implement me
+	panic("implement me")
+}
+
+func (m mockCmix) DeleteClientService(clientID *id.ID) {
+	//TODO implement me
+	panic("implement me")
+}
+
+func (m mockCmix) TrackServices(tracker message.ServicesTracker) {
+	//TODO implement me
+	panic("implement me")
+}
+
+func (m mockCmix) CheckInProgressMessages() {
+	//TODO implement me
+	panic("implement me")
+}
+
+func (m mockCmix) IsHealthy() bool {
+	//TODO implement me
+	panic("implement me")
+}
+
+func (m mockCmix) WasHealthy() bool {
+	//TODO implement me
+	panic("implement me")
+}
+
+func (m mockCmix) AddHealthCallback(f func(bool)) uint64 {
+	//TODO implement me
+	panic("implement me")
+}
+
+func (m mockCmix) RemoveHealthCallback(u uint64) {
+	//TODO implement me
+	panic("implement me")
+}
+
+func (m mockCmix) HasNode(nid *id.ID) bool {
+	//TODO implement me
+	panic("implement me")
+}
+
+func (m mockCmix) NumRegisteredNodes() int {
+	//TODO implement me
+	panic("implement me")
+}
+
+func (m mockCmix) TriggerNodeRegistration(nid *id.ID) {
+	//TODO implement me
+	panic("implement me")
+}
+
+func (m mockCmix) GetRoundResults(timeout time.Duration, roundCallback cmix.RoundEventCallback, roundList ...id.Round) {
+	//TODO implement me
+	panic("implement me")
+}
+
+func (m mockCmix) LookupHistoricalRound(rid id.Round, callback rounds.RoundResultCallback) error {
+	//TODO implement me
+	panic("implement me")
+}
+
+func (m mockCmix) SendToAny(sendFunc func(host *connect.Host) (interface{}, error), stop *stoppable.Single) (interface{}, error) {
+	//TODO implement me
+	panic("implement me")
+}
+
+func (m mockCmix) SendToPreferred(targets []*id.ID, sendFunc gateway.SendToPreferredFunc, stop *stoppable.Single, timeout time.Duration) (interface{}, error) {
+	//TODO implement me
+	panic("implement me")
+}
+
+func (m mockCmix) SetGatewayFilter(f gateway.Filter) {
+	//TODO implement me
+	panic("implement me")
+}
+
+func (m mockCmix) GetHostParams() connect.HostParams {
+	//TODO implement me
+	panic("implement me")
+}
+
+func (m mockCmix) GetAddressSpace() uint8 {
+	//TODO implement me
+	panic("implement me")
+}
+
+func (m mockCmix) RegisterAddressSpaceNotification(tag string) (chan uint8, error) {
+	//TODO implement me
+	panic("implement me")
+}
+
+func (m mockCmix) UnregisterAddressSpaceNotification(tag string) {
+	//TODO implement me
+	panic("implement me")
+}
+
+func (m mockCmix) GetInstance() *network.Instance {
+	//TODO implement me
+	panic("implement me")
+}
+
+func (m mockCmix) GetVerboseRounds() string {
+	//TODO implement me
+	panic("implement me")
+}
diff --git a/dummy/random.go b/dummy/random.go
index 8c8a87a6cc0328f136f2444125cde62c92972a0b..2a41d8243decc43ae56ae93068c5106a8f9371e7 100644
--- a/dummy/random.go
+++ b/dummy/random.go
@@ -1,8 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package dummy
@@ -10,42 +10,77 @@ package dummy
 import (
 	"encoding/binary"
 	"github.com/pkg/errors"
+	"gitlab.com/elixxir/client/cmix/message"
 	"gitlab.com/elixxir/primitives/format"
 	"gitlab.com/xx_network/crypto/csprng"
+	"gitlab.com/xx_network/primitives/id"
 	"time"
 ) // Error messages.
 
+// Error constants for Manager.newRandomCmixMessage and it's helper functions..
 const (
 	payloadSizeRngErr = "failed to generate random payload size: %+v"
+	payloadRngErr     = "failed to generate random payload: %+v"
+	fingerprintRngErr = "failed to generate random fingerprint: %+v"
+	macRngErr         = "failed to generate random MAC: %+v"
+	recipientRngErr   = "failed to generate random recipient: %+v"
 )
 
-// intRng returns, as an int, a non-negative, non-zero random number in [1, n)
-// from the csprng.Source.
-func intRng(n int, rng csprng.Source) (int, error) {
-	v, err := csprng.Generate(8, rng)
+// newRandomCmixMessage returns random format.Message data.
+//
+// Returns in order a:
+//  - Recipient (id.ID)
+//  - Message fingerprint (format.Fingerprint)
+//  - Message service (message.Service)
+//  - Payload ([]byte)
+//  - MAC ([]byte)
+//  - Error if there was an issue randomly generating any of the above data.
+//    The error will specify which of the above failed to be randomly generated.
+func (m *Manager) newRandomCmixMessage(rng csprng.Source) (
+	recipient *id.ID, fingerprint format.Fingerprint,
+	service message.Service,
+	payload, mac []byte, err error) {
+
+	// Generate random recipient
+	recipient, err = id.NewRandomID(rng, id.User)
 	if err != nil {
-		return 0, err
+		return nil, format.Fingerprint{}, message.Service{}, nil, nil,
+			errors.Errorf(recipientRngErr, err)
 	}
 
-	return int(binary.LittleEndian.Uint64(v)%uint64(n-1)) + 1, nil
-}
+	// Generate random message payload
+	payloadSize := m.store.GetCmixGroup().GetP().ByteLen()
+	payload, err = newRandomPayload(payloadSize, rng)
+	if err != nil {
+		return nil, format.Fingerprint{}, message.Service{}, nil, nil,
+			errors.Errorf(payloadRngErr, err)
+	}
 
-// durationRng returns a duration that is the base duration plus or minus a
-// random duration of max randomRange.
-func durationRng(base, randomRange time.Duration, rng csprng.Source) (
-	time.Duration, error) {
-	delta, err := intRng(int(2*randomRange), rng)
+	// Generate random fingerprint
+	fingerprint, err = newRandomFingerprint(rng)
 	if err != nil {
-		return 0, err
+		return nil, format.Fingerprint{}, message.Service{}, nil, nil,
+			errors.Errorf(fingerprintRngErr, err)
 	}
 
-	return base + randomRange - time.Duration(delta), nil
+	// Generate random MAC
+	mac, err = newRandomMAC(rng)
+	if err != nil {
+		return nil, format.Fingerprint{}, message.Service{}, nil, nil,
+			errors.Errorf(macRngErr, err)
+	}
+
+	// Generate random service
+	service = message.GetRandomService(rng)
+
+	return
 }
 
-// newRandomPayload generates a random payload of a random length.
+// newRandomPayload generates a random payload of a random length
+// within the maxPayloadSize.
 func newRandomPayload(maxPayloadSize int, rng csprng.Source) ([]byte, error) {
 	// Generate random payload size
-	randomPayloadSize, err := intRng(maxPayloadSize, rng)
+	randomPayloadSize, err := randomInt(maxPayloadSize, rng)
 	if err != nil {
 		return nil, errors.Errorf(payloadSizeRngErr, err)
 	}
@@ -86,3 +121,32 @@ func newRandomMAC(rng csprng.Source) ([]byte, error) {
 
 	return mac, nil
 }
+
+//////////////////////////////////////////////////////////////////////////////////
+// Miscellaneous
+//////////////////////////////////////////////////////////////////////////////////
+
+// randomDuration returns a duration that is the base duration plus or minus a
+// random duration of max randomRange.
+func randomDuration(base, randomRange time.Duration, rng csprng.Source) (
+	time.Duration, error) {
+
+	// Generate a random duration
+	delta, err := randomInt(int(2*randomRange), rng)
+	if err != nil {
+		return 0, err
+	}
+
+	return base + randomRange - time.Duration(delta), nil
+}
+
+// randomInt returns, as an int, a non-negative, non-zero random number in [1, n)
+// from the csprng.Source.
+func randomInt(n int, rng csprng.Source) (int, error) {
+	v, err := csprng.Generate(8, rng)
+	if err != nil {
+		return 0, err
+	}
+
+	return int(binary.LittleEndian.Uint64(v)%uint64(n-1)) + 1, nil
+}
diff --git a/dummy/random_test.go b/dummy/random_test.go
index 661986a0416993e211209d009a023c451dd3ff60..fab84c22fc0e552931026ec0f27cc0c07e511b32 100644
--- a/dummy/random_test.go
+++ b/dummy/random_test.go
@@ -1,8 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package dummy
@@ -13,7 +13,7 @@ import (
 	"time"
 )
 
-// Consistency test: tests that intRng returns the expected int when using a
+// Consistency test: tests that randomInt returns the expected int when using a
 // PRNG and that the result is not larger than the max.
 func Test_intRng_Consistency(t *testing.T) {
 	expectedInts := []int{15, 1, 35, 13, 42, 52, 57, 3, 48}
@@ -22,9 +22,9 @@ func Test_intRng_Consistency(t *testing.T) {
 	max := 64
 
 	for i, expected := range expectedInts {
-		v, err := intRng(max, prng)
+		v, err := randomInt(max, prng)
 		if err != nil {
-			t.Errorf("intRng returned an error (%d): %+v", i, err)
+			t.Errorf("randomInt returned an error (%d): %+v", i, err)
 		}
 
 		if v != expected {
@@ -40,7 +40,7 @@ func Test_intRng_Consistency(t *testing.T) {
 	}
 }
 
-// Consistency test: tests that durationRng returns the expected int when using
+// Consistency test: tests that randomDuration returns the expected int when using
 // a PRNG and that the result is within the allowed range.
 func Test_durationRng_Consistency(t *testing.T) {
 	expectedDurations := []time.Duration{
@@ -52,9 +52,9 @@ func Test_durationRng_Consistency(t *testing.T) {
 	base, randomRange := time.Minute, 15*time.Second
 
 	for i, expected := range expectedDurations {
-		v, err := durationRng(base, randomRange, prng)
+		v, err := randomDuration(base, randomRange, prng)
 		if err != nil {
-			t.Errorf("durationRng returned an error (%d): %+v", i, err)
+			t.Errorf("randomDuration returned an error (%d): %+v", i, err)
 		}
 
 		if v != expected {
diff --git a/dummy/send.go b/dummy/send.go
index 84271b67ea4310bf91af057a58ffe2256520460a..ac6b39796add64bbfed8be9ed8c3e3f8687904f8 100644
--- a/dummy/send.go
+++ b/dummy/send.go
@@ -1,199 +1,144 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package dummy
 
 import (
+	"gitlab.com/elixxir/client/cmix"
+	"gitlab.com/xx_network/crypto/csprng"
 	"sync"
 	"sync/atomic"
 	"time"
 
 	"github.com/pkg/errors"
 	jww "github.com/spf13/jwalterweatherman"
-	"gitlab.com/elixxir/client/cmix"
 	"gitlab.com/elixxir/client/stoppable"
-	"gitlab.com/elixxir/primitives/format"
-	"gitlab.com/xx_network/crypto/csprng"
-	"gitlab.com/xx_network/primitives/id"
 )
 
-// Error messages.
+// Error messages for the Manager.sendThread and its helper functions.
 const (
-	numMsgsRngErr     = "failed to generate random number of messages to send: %+v"
-	payloadRngErr     = "failed to generate random payload: %+v"
-	recipientRngErr   = "failed to generate random recipient: %+v"
-	fingerprintRngErr = "failed to generate random fingerprint: %+v"
-	macRngErr         = "failed to generate random MAC: %+v"
+	numMsgsRngErr = "failed to generate random number of messages to send: %+v"
 )
 
 // sendThread is a thread that sends the dummy messages at random intervals.
 func (m *Manager) sendThread(stop *stoppable.Single) {
-	jww.DEBUG.Print("Starting dummy traffic sending thread.")
+	jww.INFO.Print("Starting dummy traffic sending thread.")
 
 	nextSendChan := make(<-chan time.Time)
 	nextSendChanPtr := &(nextSendChan)
 
 	for {
 		select {
-		case <-stop.Quit():
-			m.stopSendThread(stop)
-			return
 		case status := <-m.statusChan:
 			if status {
 				atomic.StoreUint32(&m.status, running)
-				nextSendChanPtr = &(m.randomTimer().C)
+				// Generate random duration
+				rng := m.rng.GetStream()
+				duration, err := randomDuration(m.avgSendDelta, m.randomRange, rng)
+				if err != nil {
+					rng.Close()
+					jww.FATAL.Panicf("Failed to generate random sending interval: %+v", err)
+				}
+				rng.Close()
+
+				// Create timer
+				nextSendChanPtr = &(time.NewTimer(duration).C)
+
 			} else {
 				atomic.StoreUint32(&m.status, paused)
 				nextSendChan = make(<-chan time.Time)
 				nextSendChanPtr = &nextSendChan
 			}
 		case <-*nextSendChanPtr:
-			nextSendChanPtr = &(m.randomTimer().C)
-
-			go func() {
-				// get list of random messages and recipients
-				rng := m.rng.GetStream()
-				msgs, err := m.newRandomMessages(rng)
-				if err != nil {
-					jww.FATAL.Panicf("Failed to generate dummy messages: %+v", err)
-				}
+			// Generate random duration
+			rng := m.rng.GetStream()
+			duration, err := randomDuration(m.avgSendDelta, m.randomRange, rng)
+			if err != nil {
 				rng.Close()
+				jww.FATAL.Panicf("Failed to generate random sending interval: %+v", err)
+			}
+			rng.Close()
+
+			// Create timer
+			nextSendChanPtr = &(time.NewTimer(duration).C)
 
-				err = m.sendMessages(msgs)
+			// Send messages
+			go func() {
+				err := m.sendMessages()
 				if err != nil {
-					jww.FATAL.Panicf("Failed to send dummy messages: %+v", err)
+					jww.ERROR.Printf("Failed to send dummy messages: %+v", err)
 				}
 			}()
+		case <-stop.Quit():
+			m.stopSendThread(stop)
+			return
 
 		}
 	}
 }
 
-// stopSendThread is triggered when the stoppable is triggered. It prints a
-// debug message, sets the thread status to stopped, and sets the status of the
-// stoppable to stopped.
-func (m *Manager) stopSendThread(stop *stoppable.Single) {
-	jww.DEBUG.Print(
-		"Stopping dummy traffic sending thread: stoppable triggered")
-	atomic.StoreUint32(&m.status, stopped)
-	stop.ToStopped()
-}
-
 // sendMessages generates and sends random messages.
-func (m *Manager) sendMessages(msgs map[id.ID]format.Message) error {
-	var sent, i int64
+func (m *Manager) sendMessages() error {
+	var sent int64
 	var wg sync.WaitGroup
 
-	for recipient, msg := range msgs {
-		wg.Add(1)
+	// Randomly generate amount of messages to send
+	rng := m.rng.GetStream()
+	defer rng.Close()
+	numMessages, err := randomInt(m.maxNumMessages+1, rng)
+	if err != nil {
+		return errors.Errorf(numMsgsRngErr, err)
+	}
 
-		go func(i int64, recipient id.ID, msg format.Message) {
+	for i := 0; i < numMessages; i++ {
+		wg.Add(1)
+		go func(localIndex, totalMessages int) {
 			defer wg.Done()
 
-			// Fill the preimage with random data to ensure it is not repeatable
-			p := cmix.GetDefaultParams()
-			// FIXME: these fields no longer available
-			//        through these params objects
-			// p.IdentityPreimage = make([]byte, 32)
-			// rng := m.rng.GetStream()
-			// if _, err := rng.Read(p.IdentityPreimage); err != nil {
-			// 	jww.FATAL.Panicf("Failed to generate data for random identity "+
-			// 		"preimage in e2e send: %+v", err)
-			// }
-			// rng.Close()
-			// p.DebugTag = "dummy"
-			_, _, err := m.networkManager.SendCMIX(msg, &recipient, p)
+			err = m.sendMessage(localIndex, totalMessages, rng)
 			if err != nil {
-				jww.WARN.Printf("Failed to send dummy message %d/%d via "+
-					"Send: %+v", i, len(msgs), err)
-			} else {
-				atomic.AddInt64(&sent, 1)
+				jww.ERROR.Printf("Failed to send message %d/%d: %+v",
+					localIndex, numMessages, err)
 			}
-		}(i, recipient, msg)
-
-		i++
+			// Add to counter of successful sends
+			atomic.AddInt64(&sent, 1)
+		}(i, numMessages)
 	}
 
 	wg.Wait()
-
-	jww.INFO.Printf("Sent %d/%d dummy messages.", sent, len(msgs))
-
+	jww.INFO.Printf("Sent %d/%d dummy messages.", sent, numMessages)
 	return nil
 }
 
-// newRandomMessages returns a map of a random recipients and random messages of
-// a randomly generated length in [1, Manager.maxNumMessages].
-func (m *Manager) newRandomMessages(rng csprng.Source) (
-	map[id.ID]format.Message, error) {
-	numMessages, err := intRng(m.maxNumMessages+1, rng)
-	if err != nil {
-		return nil, errors.Errorf(numMsgsRngErr, err)
-	}
-
-	msgs := make(map[id.ID]format.Message, numMessages)
-
-	for i := 0; i < numMessages; i++ {
-		// Generate random recipient
-		recipient, err := id.NewRandomID(rng, id.User)
-		if err != nil {
-			return nil, errors.Errorf(recipientRngErr, err)
-		}
-
-		msgs[*recipient], err = m.newRandomCmixMessage(rng)
-		if err != nil {
-			return nil, err
-		}
-	}
-
-	return msgs, nil
-}
-
-// newRandomCmixMessage returns a new cMix message filled with a randomly
-// generated payload, fingerprint, and MAC.
-func (m *Manager) newRandomCmixMessage(rng csprng.Source) (format.Message, error) {
-	// Create new empty cMix message
-	clientStorage := *m.store
-	cMixMsg := format.NewMessage(clientStorage.GetCmixGroup().GetP().ByteLen())
-
-	// Generate random message
-	randomMsg, err := newRandomPayload(cMixMsg.ContentsSize(), rng)
+// sendMessage is a helper function which generates a sends a single random format.Message
+// to a random recipient.
+func (m *Manager) sendMessage(index, totalMessages int, rng csprng.Source) error {
+	// Generate message data
+	recipient, fp, service, payload, mac, err := m.newRandomCmixMessage(rng)
 	if err != nil {
-		return format.Message{}, errors.Errorf(payloadRngErr, err)
+		return errors.Errorf("Failed to create random data: %+v", err)
 	}
 
-	// Generate random fingerprint
-	fingerprint, err := newRandomFingerprint(rng)
+	// Send message
+	p := cmix.GetDefaultCMIXParams()
+	_, _, err = m.net.Send(recipient, fp, service, payload, mac, p)
 	if err != nil {
-		return format.Message{}, errors.Errorf(fingerprintRngErr, err)
+		return errors.Errorf("Failed to send message: %+v", err)
 	}
 
-	// Generate random MAC
-	mac, err := newRandomMAC(rng)
-	if err != nil {
-		return format.Message{}, errors.Errorf(macRngErr, err)
-	}
-
-	// Set contents, fingerprint, and MAC, of the cMix message
-	cMixMsg.SetContents(randomMsg)
-	cMixMsg.SetKeyFP(fingerprint)
-	cMixMsg.SetMac(mac)
-
-	return cMixMsg, nil
+	return nil
 }
 
-// randomTimer generates a timer that will trigger after a random duration.
-func (m *Manager) randomTimer() *time.Timer {
-	rng := m.rng.GetStream()
-
-	duration, err := durationRng(m.avgSendDelta, m.randomRange, rng)
-	if err != nil {
-		jww.FATAL.Panicf("Failed to generate random duration to wait to send "+
-			"dummy messages: %+v", err)
-	}
-
-	return time.NewTimer(duration)
+// stopSendThread is triggered when the stoppable is triggered. It prints a
+// debug message, sets the thread status to stopped, and sets the status of the
+// stoppable to stopped.
+func (m *Manager) stopSendThread(stop *stoppable.Single) {
+	jww.DEBUG.Print(
+		"Stopping dummy traffic sending thread: stoppable triggered")
+	atomic.StoreUint32(&m.status, stopped)
+	stop.ToStopped()
 }
diff --git a/dummy/send_test.go b/dummy/send_test.go
index 9af8ee8796e4d76faa7d45188c60db271d772335..edc4b4e2f83f41da04dfe12c2111fc553fc528c9 100644
--- a/dummy/send_test.go
+++ b/dummy/send_test.go
@@ -1,15 +1,14 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package dummy
 
 import (
 	"bytes"
-	"encoding/base64"
 	"gitlab.com/elixxir/client/stoppable"
 	"gitlab.com/elixxir/primitives/format"
 	"gitlab.com/xx_network/primitives/id"
@@ -21,7 +20,7 @@ import (
 
 // Tests that Manager.sendThread sends multiple sets of messages.
 func TestManager_sendThread(t *testing.T) {
-	m := newTestManager(10, 50*time.Millisecond, 10*time.Millisecond, false, t)
+	m := newTestManager(10, 50*time.Millisecond, 10*time.Millisecond, t)
 
 	stop := stoppable.NewSingle("sendThreadTest")
 	go m.sendThread(stop)
@@ -40,10 +39,10 @@ func TestManager_sendThread(t *testing.T) {
 	go func() {
 		var numReceived int
 		for i := 0; i < 2; i++ {
-			for m.networkManager.(*testNetworkManager).GetMsgListLen() == numReceived {
+			for m.net.(*mockCmix).GetMsgListLen() == numReceived {
 				time.Sleep(5 * time.Millisecond)
 			}
-			numReceived = m.networkManager.(*testNetworkManager).GetMsgListLen()
+			numReceived = m.net.(*mockCmix).GetMsgListLen()
 			msgChan <- true
 		}
 	}()
@@ -54,7 +53,7 @@ func TestManager_sendThread(t *testing.T) {
 		t.Errorf("Timed out after %s waiting for messages to be sent.",
 			3*m.avgSendDelta)
 	case <-msgChan:
-		numReceived += m.networkManager.(*testNetworkManager).GetMsgListLen()
+		numReceived += m.net.(*mockCmix).GetMsgListLen()
 	}
 
 	select {
@@ -62,10 +61,10 @@ func TestManager_sendThread(t *testing.T) {
 		t.Errorf("Timed out after %s waiting for messages to be sent.",
 			3*m.avgSendDelta)
 	case <-msgChan:
-		if m.networkManager.(*testNetworkManager).GetMsgListLen() <= numReceived {
+		if m.net.(*mockCmix).GetMsgListLen() <= numReceived {
 			t.Errorf("Failed to receive second send."+
 				"\nmessages on last receive: %d\nmessages on this receive: %d",
-				numReceived, m.networkManager.(*testNetworkManager).GetMsgListLen())
+				numReceived, m.net.(*mockCmix).GetMsgListLen())
 		}
 	}
 
@@ -86,36 +85,37 @@ func TestManager_sendThread(t *testing.T) {
 
 }
 
-// Tests that Manager.sendMessages sends all the messages with the correct
-// recipient.
-func TestManager_sendMessages(t *testing.T) {
-	m := newTestManager(100, 0, 0, false, t)
-	prng := NewPrng(42)
+// Tests that sendMessage generates random message data using pseudo-RNGs.
+func TestManager_sendMessage(t *testing.T) {
+	m := newTestManager(100, 0, 0, t)
+
+	// Generate two identical RNGs, one for generating expected data (newRandomCmixMessage)
+	// and one for received data (sendMessage)
+	prngOne := NewPrng(42)
+	prngTwo := NewPrng(42)
 
 	// Generate map of recipients and messages
 	msgs := make(map[id.ID]format.Message, m.maxNumMessages)
 	for i := 0; i < m.maxNumMessages; i++ {
-		recipient, err := id.NewRandomID(prng, id.User)
+		// Generate random data
+		recipient, fp, service, payload, mac, err := m.newRandomCmixMessage(prngOne)
 		if err != nil {
-			t.Errorf("Failed to generate random recipient ID (%d): %+v", i, err)
+			t.Fatalf("Failed to generate random cMix message (%d): %+v", i, err)
 		}
 
-		msg, err := m.newRandomCmixMessage(prng)
+		payloadSize := m.store.GetCmixGroup().GetP().ByteLen()
+		msgs[*recipient] = generateMessage(payloadSize, fp, service, payload, mac)
+
+		// Send the messages
+		err = m.sendMessage(i, m.maxNumMessages, prngTwo)
 		if err != nil {
-			t.Errorf("Failed to generate random cMix message (%d): %+v", i, err)
+			t.Errorf("sendMessages returned an error: %+v", err)
 		}
 
-		msgs[*recipient] = msg
-	}
-
-	// Send the messages
-	err := m.sendMessages(msgs)
-	if err != nil {
-		t.Errorf("sendMessages returned an error: %+v", err)
 	}
 
 	// get sent messages
-	receivedMsgs := m.networkManager.(*testNetworkManager).GetMsgList()
+	receivedMsgs := m.net.(*mockCmix).GetMsgList()
 
 	// Test that all messages were received
 	if len(receivedMsgs) != len(msgs) {
@@ -127,60 +127,46 @@ func TestManager_sendMessages(t *testing.T) {
 	for recipient, msg := range msgs {
 		receivedMsg, exists := receivedMsgs[recipient]
 		if !exists {
-			t.Errorf("Failed to receive message from %s: %+v", &recipient, msg)
-		} else if !reflect.DeepEqual(msg, receivedMsg) {
+			t.Errorf("Failed to receive message from %s: %+v", &recipient, msg.Marshal())
+		} else if !reflect.DeepEqual(msg.Marshal(), receivedMsg.Marshal()) {
+			// In mockCmix.Send, we map recipientId to the passed fingerprint.
 			t.Errorf("Received unexpected message for recipient %s."+
 				"\nexpected: %+v\nreceived: %+v", &recipient, msg, receivedMsg)
 		}
 	}
 }
 
-// Tests that Manager.newRandomMessages creates a non-empty map of messages and
-// that each message is unique.
-func TestManager_newRandomMessages(t *testing.T) {
-	m := newTestManager(10, 0, 0, false, t)
+// Tests that newRandomCmixMessage generates cMix message data with
+// populated recipient, payload, fingerprint, and MAC.
+func TestManager_newRandomCmixMessage(t *testing.T) {
+	m := newTestManager(0, 0, 0, t)
 	prng := NewPrng(42)
 
-	msgMap, err := m.newRandomMessages(prng)
+	// Generate data
+	recipient, fp, _, payload, mac, err := m.newRandomCmixMessage(prng)
 	if err != nil {
-		t.Errorf("newRandomMessages returned an error: %+v", err)
-	}
-
-	if len(msgMap) == 0 {
-		t.Error("Message map is empty.")
+		t.Fatalf("newRandomCmixMessage returned an error: %+v", err)
 	}
 
-	marshalledMsgs := make(map[string]format.Message, len(msgMap))
-	for _, msg := range msgMap {
-		msgString := base64.StdEncoding.EncodeToString(msg.Marshal())
-		if _, exists := marshalledMsgs[msgString]; exists {
-			t.Errorf("Message not unique.")
-		} else {
-			marshalledMsgs[msgString] = msg
-		}
+	// Check that recipient is not empty data
+	if bytes.Equal(recipient.Bytes(), make([]byte, id.ArrIDLen)) {
+		t.Errorf("Recipient ID not set")
 	}
-}
-
-// Tests that Manager.newRandomCmixMessage generates a cMix message with
-// populated contents, fingerprint, and MAC.
-func TestManager_newRandomCmixMessage(t *testing.T) {
-	m := newTestManager(0, 0, 0, false, t)
-	prng := NewPrng(42)
 
-	cMixMsg, err := m.newRandomCmixMessage(prng)
-	if err != nil {
-		t.Errorf("newRandomCmixMessage returned an error: %+v", err)
-	}
-
-	if bytes.Equal(cMixMsg.GetContents(), make([]byte, len(cMixMsg.GetContents()))) {
+	// Check that payload is not empty data
+	payloadSize := m.store.GetCmixGroup().GetP().ByteLen()
+	if bytes.Equal(payload, make([]byte, payloadSize)) {
 		t.Error("cMix message contents not set.")
 	}
 
-	if cMixMsg.GetKeyFP() == (format.Fingerprint{}) {
+	// Check that fingerprint is not empty data
+	if fp == (format.Fingerprint{}) {
 		t.Error("cMix message fingerprint not set.")
 	}
 
-	if bytes.Equal(cMixMsg.GetMac(), make([]byte, format.MacLen)) {
+	// Check that mac is not empty data
+	if bytes.Equal(mac, make([]byte, format.MacLen)) {
 		t.Error("cMix message MAC not set.")
 	}
+
 }
diff --git a/dummy/utils_test.go b/dummy/utils_test.go
index bc838731f5f42b345c4fbdfd849750b4551c0ef5..4ddccebf7cf5ccb4371fa31f6811bb319612fac1 100644
--- a/dummy/utils_test.go
+++ b/dummy/utils_test.go
@@ -1,34 +1,20 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package dummy
 
 import (
-	"github.com/pkg/errors"
-	"gitlab.com/elixxir/client/cmix"
-	"gitlab.com/elixxir/client/cmix/gateway"
 	"gitlab.com/elixxir/client/cmix/message"
-	"gitlab.com/elixxir/client/event"
-	"gitlab.com/elixxir/client/interfaces"
-	"gitlab.com/elixxir/client/stoppable"
 	"gitlab.com/elixxir/client/storage"
-	"gitlab.com/elixxir/comms/mixmessages"
-	"gitlab.com/elixxir/comms/network"
-	"gitlab.com/elixxir/crypto/e2e"
 	"gitlab.com/elixxir/crypto/fastRNG"
 	"gitlab.com/elixxir/primitives/format"
-	"gitlab.com/xx_network/comms/connect"
 	"gitlab.com/xx_network/crypto/csprng"
-	"gitlab.com/xx_network/primitives/id"
-	"gitlab.com/xx_network/primitives/id/ephemeral"
-	"gitlab.com/xx_network/primitives/ndf"
 	"io"
 	"math/rand"
-	"sync"
 	"testing"
 	"time"
 )
@@ -51,201 +37,35 @@ func (s *Prng) SetSeed([]byte) error       { return nil }
 // newTestManager creates a new Manager that has groups stored for testing. One
 // of the groups in the list is also returned.
 func newTestManager(maxNumMessages int, avgSendDelta, randomRange time.Duration,
-	sendErr bool, t *testing.T) *Manager {
+	t *testing.T) *Manager {
 	store := storage.InitTestingSession(t)
+	payloadSize := store.GetCmixGroup().GetP().ByteLen()
 	m := &Manager{
 		maxNumMessages: maxNumMessages,
 		avgSendDelta:   avgSendDelta,
 		randomRange:    randomRange,
 		statusChan:     make(chan bool, statusChanLen),
-		store:          &store,
-		networkManager: newTestNetworkManager(sendErr, t),
+		store:          store,
+		net:            newMockCmix(payloadSize),
 		rng:            fastRNG.NewStreamGenerator(1000, 10, csprng.NewSystemRNG),
 	}
 
 	return m
 }
 
-// ////////////////////////////////////////////////////////////////////////////////
-// // Test Network State                                                       //
-// ////////////////////////////////////////////////////////////////////////////////
-
-// // testNetworkManager is a test implementation of NetworkManager interface.
-type testNetworkManager struct {
-	instance *network.Instance
-	messages map[id.ID]format.Message
-	sendErr  bool
-	sync.RWMutex
-}
-
-func newTestNetworkManager(sendErr bool, t *testing.T) interfaces.NetworkManager {
-	instanceComms := &connect.ProtoComms{
-		Manager: connect.NewManagerTesting(t),
-	}
-
-	thisInstance, err := network.NewInstanceTesting(instanceComms, getNDF(),
-		getNDF(), nil, nil, t)
-	if err != nil {
-		t.Fatalf("Failed to create new test instance: %v", err)
-	}
-
-	return &testNetworkManager{
-		instance: thisInstance,
-		messages: make(map[id.ID]format.Message),
-		sendErr:  sendErr,
-	}
-}
-
-func (tnm *testNetworkManager) GetMsgListLen() int {
-	tnm.RLock()
-	defer tnm.RUnlock()
-	return len(tnm.messages)
-}
-
-func (tnm *testNetworkManager) GetMsgList() map[id.ID]format.Message {
-	tnm.RLock()
-	defer tnm.RUnlock()
-	return tnm.messages
-}
-
-func (tnm *testNetworkManager) GetMsg(recipient id.ID) format.Message {
-	tnm.RLock()
-	defer tnm.RUnlock()
-	return tnm.messages[recipient]
-}
-
-// TEST
-func (tnm *testNetworkManager) SendE2E() (
-	[]id.Round, e2e.MessageID, time.Time, error) {
-	return nil, e2e.MessageID{}, time.Time{}, nil
-}
-
-// TEST
-func (tnm *testNetworkManager) SendUnsafe() ([]id.Round, error) {
-	return []id.Round{}, nil
-}
-
-func (tnm *testNetworkManager) SendCMIX(message format.Message,
-	recipient *id.ID, _ cmix.Params) (id.Round, ephemeral.Id, error) {
-	tnm.Lock()
-	defer tnm.Unlock()
-
-	if tnm.sendErr {
-		return 0, ephemeral.Id{}, errors.New("Send error")
-	}
+// generateMessage is a utility function which generates a format.Message
+// given message data.
+func generateMessage(payloadSize int,
+	fingerprint format.Fingerprint,
+	service message.Service,
+	payload, mac []byte) format.Message {
 
-	tnm.messages[*recipient] = message
+	// Build message. Will panic if inputs are not correct.
+	msg := format.NewMessage(payloadSize)
+	msg.SetContents(payload)
+	msg.SetKeyFP(fingerprint)
+	msg.SetSIH(service.Hash(msg.GetContents()))
+	msg.SetMac(mac)
 
-	return 0, ephemeral.Id{}, nil
-}
-
-func (tnm *testNetworkManager) SendManyCMIX([]cmix.TargetedCmixMessage, cmix.Params) (
-	id.Round, []ephemeral.Id, error) {
-	return 0, nil, nil
-}
-
-type dummyEventMgr struct{}
-
-func (d *dummyEventMgr) Report(int, string, string, string) {}
-func (tnm *testNetworkManager) GetEventManager() event.Reporter {
-	return &dummyEventMgr{}
-}
-
-func (tnm *testNetworkManager) GetInstance() *network.Instance             { return tnm.instance }
-func (tnm *testNetworkManager) GetAddressSpace() uint8                     { return 0 }
-func (tnm *testNetworkManager) GetHostParams() connect.HostParams          { return connect.HostParams{} }
-func (tnm *testNetworkManager) GetHealthTracker() interfaces.HealthTracker { return nil }
-func (tnm *testNetworkManager) Follow(interfaces.ClientErrorReport) (stoppable.Stoppable, error) {
-	return nil, nil
-}
-func (tnm *testNetworkManager) CheckGarbledMessages()        {}
-func (tnm *testNetworkManager) CheckInProgressMessages()     {}
-func (tnm *testNetworkManager) InProgressRegistrations() int { return 0 }
-func (tnm *testNetworkManager) GetSender() *gateway.Sender   { return nil }
-func (tnm *testNetworkManager) GetAddressSize() uint8        { return 0 }
-func (tnm *testNetworkManager) RegisterAddressSizeNotification(string) (chan uint8, error) {
-	return nil, nil
-}
-func (tnm *testNetworkManager) UnregisterAddressSizeNotification(string) {}
-func (tnm *testNetworkManager) SetPoolFilter(gateway.Filter)             {}
-func (tnm *testNetworkManager) GetVerboseRounds() string                 { return "" }
-func (tnm *testNetworkManager) HasNode(*id.ID) bool                      { return false }
-func (tnm *testNetworkManager) LookupHistoricalRound(id.Round, func(*mixmessages.RoundInfo, bool)) error {
-	return nil
-}
-func (tnm *testNetworkManager) NumRegisteredNodes() int { return 0 }
-func (tnm *testNetworkManager) RegisterAddressSpaceNotification(string) (chan uint8, error) {
-	return nil, nil
-}
-func (tnm *testNetworkManager) SendToAny(func(*connect.Host) (interface{}, error), *stoppable.Single) (interface{}, error) {
-	return nil, nil
-}
-func (tnm *testNetworkManager) SendToPreferred([]*id.ID, func(*connect.Host, *id.ID, time.Duration) (interface{}, error), *stoppable.Single, time.Duration) (interface{}, error) {
-	return nil, nil
-}
-func (tnm *testNetworkManager) SetGatewayFilter(func(map[id.ID]int, *ndf.NetworkDefinition) map[id.ID]int) {
-}
-func (tnm *testNetworkManager) TrackServices(message.ServicesTracker)     {}
-func (tnm *testNetworkManager) TriggerNodeRegistration(*id.ID)            {}
-func (tnm *testNetworkManager) UnregisterAddressSpaceNotification(string) {}
-
-func (tnm *testNetworkManager) AddFingerprint(*id.ID, format.Fingerprint, message.Processor) error {
-	return nil
-}
-func (tnm *testNetworkManager) DeleteFingerprint(*id.ID, format.Fingerprint) {}
-func (tnm *testNetworkManager) DeleteClientFingerprints(*id.ID)              {}
-
-func (tnm *testNetworkManager) AddIdentity(*id.ID, time.Time, bool) error { return nil }
-func (tnm *testNetworkManager) RemoveIdentity(*id.ID)                     {}
-
-func (tnm *testNetworkManager) AddTrigger(*id.ID, message.Service, message.Processor) {}
-func (tnm *testNetworkManager) DeleteTrigger(*id.ID, interfaces.Preimage, message.Processor) error {
-	return nil
-}
-func (tnm *testNetworkManager) DeleteClientTriggers(*id.ID) {}
-
-// ////////////////////////////////////////////////////////////////////////////////
-// // NDF Primes                                                                 //
-// ////////////////////////////////////////////////////////////////////////////////
-
-func getNDF() *ndf.NetworkDefinition {
-	return &ndf.NetworkDefinition{
-		E2E: ndf.Group{
-			Prime: "E2EE983D031DC1DB6F1A7A67DF0E9A8E5561DB8E8D49413394C049B7A" +
-				"8ACCEDC298708F121951D9CF920EC5D146727AA4AE535B0922C688B55B3D" +
-				"D2AEDF6C01C94764DAB937935AA83BE36E67760713AB44A6337C20E78615" +
-				"75E745D31F8B9E9AD8412118C62A3E2E29DF46B0864D0C951C394A5CBBDC" +
-				"6ADC718DD2A3E041023DBB5AB23EBB4742DE9C1687B5B34FA48C3521632C" +
-				"4A530E8FFB1BC51DADDF453B0B2717C2BC6669ED76B4BDD5C9FF558E88F2" +
-				"6E5785302BEDBCA23EAC5ACE92096EE8A60642FB61E8F3D24990B8CB12EE" +
-				"448EEF78E184C7242DD161C7738F32BF29A841698978825B4111B4BC3E1E" +
-				"198455095958333D776D8B2BEEED3A1A1A221A6E37E664A64B83981C46FF" +
-				"DDC1A45E3D5211AAF8BFBC072768C4F50D7D7803D2D4F278DE8014A47323" +
-				"631D7E064DE81C0C6BFA43EF0E6998860F1390B5D3FEACAF1696015CB79C" +
-				"3F9C2D93D961120CD0E5F12CBB687EAB045241F96789C38E89D796138E63" +
-				"19BE62E35D87B1048CA28BE389B575E994DCA755471584A09EC723742DC3" +
-				"5873847AEF49F66E43873",
-			Generator: "2",
-		},
-		CMIX: ndf.Group{
-			Prime: "9DB6FB5951B66BB6FE1E140F1D2CE5502374161FD6538DF1648218642" +
-				"F0B5C48C8F7A41AADFA187324B87674FA1822B00F1ECF8136943D7C55757" +
-				"264E5A1A44FFE012E9936E00C1D3E9310B01C7D179805D3058B2A9F4BB6F" +
-				"9716BFE6117C6B5B3CC4D9BE341104AD4A80AD6C94E005F4B993E14F091E" +
-				"B51743BF33050C38DE235567E1B34C3D6A5C0CEAA1A0F368213C3D19843D" +
-				"0B4B09DCB9FC72D39C8DE41F1BF14D4BB4563CA28371621CAD3324B6A2D3" +
-				"92145BEBFAC748805236F5CA2FE92B871CD8F9C36D3292B5509CA8CAA77A" +
-				"2ADFC7BFD77DDA6F71125A7456FEA153E433256A2261C6A06ED3693797E7" +
-				"995FAD5AABBCFBE3EDA2741E375404AE25B",
-			Generator: "5C7FF6B06F8F143FE8288433493E4769C4D988ACE5BE25A0E2480" +
-				"9670716C613D7B0CEE6932F8FAA7C44D2CB24523DA53FBE4F6EC3595892D" +
-				"1AA58C4328A06C46A15662E7EAA703A1DECF8BBB2D05DBE2EB956C142A33" +
-				"8661D10461C0D135472085057F3494309FFA73C611F78B32ADBB5740C361" +
-				"C9F35BE90997DB2014E2EF5AA61782F52ABEB8BD6432C4DD097BC5423B28" +
-				"5DAFB60DC364E8161F4A2A35ACA3A10B1C4D203CC76A470A33AFDCBDD929" +
-				"59859ABD8B56E1725252D78EAC66E71BA9AE3F1DD2487199874393CD4D83" +
-				"2186800654760E1E34C09E4D155179F9EC0DC4473F996BDCE6EED1CABED8" +
-				"B6F116F7AD9CF505DF0F998E34AB27514B0FFE7",
-		},
-	}
+	return msg
 }
diff --git a/e2e/callbacks.go b/e2e/callbacks.go
index 915229bd040440511c21caa0666dea6a68f5950d..8f4655a277a3ed8280bb513e7fc7475fe75ba47c 100644
--- a/e2e/callbacks.go
+++ b/e2e/callbacks.go
@@ -1,8 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package e2e
diff --git a/e2e/callbacks_test.go b/e2e/callbacks_test.go
index 327020f04304e6b960f3bc72e7c6916f9c61ad7c..ab93edae6fc38556ac12e45b920e91a8a310fe09 100644
--- a/e2e/callbacks_test.go
+++ b/e2e/callbacks_test.go
@@ -1,8 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package e2e
diff --git a/e2e/critical.go b/e2e/critical.go
index 9a803886ff81faeded4e546a8462af9e78c73dc9..ddad76743d756a225d65122a2e8fdc285d497169 100644
--- a/e2e/critical.go
+++ b/e2e/critical.go
@@ -1,6 +1,14 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package e2e
 
 import (
+	"gitlab.com/elixxir/crypto/e2e"
 	"time"
 
 	jww "github.com/spf13/jwalterweatherman"
@@ -9,7 +17,6 @@ import (
 	"gitlab.com/elixxir/client/stoppable"
 	"gitlab.com/elixxir/client/storage/versioned"
 	ds "gitlab.com/elixxir/comms/network/dataStructures"
-	"gitlab.com/elixxir/crypto/e2e"
 	"gitlab.com/elixxir/primitives/format"
 	"gitlab.com/elixxir/primitives/states"
 	"gitlab.com/xx_network/primitives/id"
@@ -29,7 +36,7 @@ type roundEventRegistrar interface {
 // anonymous function to include the structures from manager that critical is
 // not aware of.
 type criticalSender func(mt catalog.MessageType, recipient *id.ID,
-	payload []byte, params Params) ([]id.Round, e2e.MessageID, time.Time, error)
+	payload []byte, params Params) (e2e.SendReport, error)
 
 // critical is a structure that allows the auto resending of messages that must
 // be received.
@@ -138,11 +145,11 @@ func (c *critical) evaluate(stop *stoppable.Single) {
 				format.DigestContents(payload))
 
 			// Send the message
-			round, _, _, err := c.send(mt, recipient, payload,
+			sendReport, err := c.send(mt, recipient, payload,
 				params)
 
 			// Pass to the handler
-			c.handle(mt, recipient, payload, round, err)
+			c.handle(mt, recipient, payload, sendReport.RoundList, err)
 		}(mt, recipient, payload, params)
 	}
 
diff --git a/e2e/e2eMessageBuffer.go b/e2e/e2eMessageBuffer.go
index 00b196d6bd70d9c5dafe7e3915e1786d89581b61..3b47ed10b9d5d31fb0d086228e941cb9c6c6f981 100644
--- a/e2e/e2eMessageBuffer.go
+++ b/e2e/e2eMessageBuffer.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package e2e
 
@@ -51,7 +51,7 @@ func (emh *e2eMessageHandler) SaveMessage(kv *versioned.KV, m interface{},
 	}
 
 	// Save versioned object
-	return kv.Set(key, currentE2EMessageVersion, &obj)
+	return kv.Set(key, &obj)
 }
 
 // LoadMessage returns the e2eMessage with the specified key from the key value
diff --git a/e2e/e2eMessageBuffer_test.go b/e2e/e2eMessageBuffer_test.go
index 37826cfcff8dee48b705ad4f0efa7b2bd83bd6ac..782f3beeef774f6e2503c6152b40926395ca65b7 100644
--- a/e2e/e2eMessageBuffer_test.go
+++ b/e2e/e2eMessageBuffer_test.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package e2e
 
diff --git a/e2e/fpGenerator.go b/e2e/fpGenerator.go
index 5e89dd8016e3c231fd968c54bdb4824f9ceeac9c..22c77222f9c5c5f8590eb4ddd89c05a91d331013 100644
--- a/e2e/fpGenerator.go
+++ b/e2e/fpGenerator.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package e2e
 
 import (
diff --git a/e2e/fpGenerator_test.go b/e2e/fpGenerator_test.go
index ebd2d7cc381a3d3ccc908b9118b697226bb0af59..249dc5bba79fc07fb38439a64b4266a658215ee0 100644
--- a/e2e/fpGenerator_test.go
+++ b/e2e/fpGenerator_test.go
@@ -1,8 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package e2e
@@ -16,6 +16,7 @@ import (
 	"gitlab.com/elixxir/client/e2e/ratchet/partner/session"
 	"gitlab.com/elixxir/client/stoppable"
 	"gitlab.com/elixxir/comms/network"
+	"gitlab.com/elixxir/crypto/e2e"
 	"gitlab.com/elixxir/primitives/format"
 	"gitlab.com/xx_network/comms/connect"
 	"gitlab.com/xx_network/primitives/id"
@@ -90,11 +91,15 @@ type mockSessionCypher struct {
 	fp format.Fingerprint
 }
 
-func (m mockSessionCypher) GetSession() *session.Session             { return nil }
-func (m mockSessionCypher) Fingerprint() format.Fingerprint          { return m.fp }
-func (m mockSessionCypher) Encrypt([]byte) (ecrContents, mac []byte) { return nil, nil }
-func (m mockSessionCypher) Decrypt(format.Message) ([]byte, error)   { return nil, nil }
-func (m mockSessionCypher) Use()                                     {}
+func (m mockSessionCypher) GetSession() *session.Session    { return nil }
+func (m mockSessionCypher) Fingerprint() format.Fingerprint { return m.fp }
+func (m mockSessionCypher) Encrypt([]byte) (ecrContents, mac []byte, residue e2e.KeyResidue) {
+	return nil, nil, e2e.KeyResidue{}
+}
+func (m mockSessionCypher) Decrypt(format.Message) ([]byte, e2e.KeyResidue, error) {
+	return nil, e2e.KeyResidue{}, nil
+}
+func (m mockSessionCypher) Use() {}
 
 ////////////////////////////////////////////////////////////////////////////////
 // Mock cMix                                                           //
@@ -113,11 +118,15 @@ func newMockFpgCmix() *mockFpgCmix {
 
 func (m *mockFpgCmix) Follow(cmix.ClientErrorReport) (stoppable.Stoppable, error) { return nil, nil }
 func (m *mockFpgCmix) GetMaxMessageLength() int                                   { return 0 }
-func (m *mockFpgCmix) Send(*id.ID, format.Fingerprint, message.Service, []byte, []byte, cmix.CMIXParams) (id.Round, ephemeral.Id, error) {
-	return 0, ephemeral.Id{}, nil
+func (m *mockFpgCmix) Send(*id.ID, format.Fingerprint, message.Service, []byte, []byte, cmix.CMIXParams) (rounds.Round, ephemeral.Id, error) {
+	return rounds.Round{}, ephemeral.Id{}, nil
 }
-func (m *mockFpgCmix) SendMany([]cmix.TargetedCmixMessage, cmix.CMIXParams) (id.Round, []ephemeral.Id, error) {
-	return 0, nil, nil
+func (m *mockFpgCmix) SendWithAssembler(recipient *id.ID, assembler cmix.MessageAssembler,
+	cmixParams cmix.CMIXParams) (rounds.Round, ephemeral.Id, error) {
+	return rounds.Round{}, ephemeral.Id{}, nil
+}
+func (m *mockFpgCmix) SendMany([]cmix.TargetedCmixMessage, cmix.CMIXParams) (rounds.Round, []ephemeral.Id, error) {
+	return rounds.Round{}, nil, nil
 }
 func (m *mockFpgCmix) AddIdentity(*id.ID, time.Time, bool) {}
 func (m *mockFpgCmix) RemoveIdentity(*id.ID)               {}
@@ -161,8 +170,7 @@ func (m *mockFpgCmix) RemoveHealthCallback(uint64)
 func (m *mockFpgCmix) HasNode(*id.ID) bool                                      { return false }
 func (m *mockFpgCmix) NumRegisteredNodes() int                                  { return 0 }
 func (m *mockFpgCmix) TriggerNodeRegistration(*id.ID)                           {}
-func (m *mockFpgCmix) GetRoundResults(time.Duration, cmix.RoundEventCallback, ...id.Round) error {
-	return nil
+func (m *mockFpgCmix) GetRoundResults(time.Duration, cmix.RoundEventCallback, ...id.Round) {
 }
 func (m *mockFpgCmix) LookupHistoricalRound(id.Round, rounds.RoundResultCallback) error { return nil }
 func (m *mockFpgCmix) SendToAny(func(host *connect.Host) (interface{}, error), *stoppable.Single) (interface{}, error) {
diff --git a/e2e/interface.go b/e2e/interface.go
index 0578bbc719731f5d1c83a7e16330506aac8bac66..05731802b42446c49c06796a066c1bec3d74ffbd 100644
--- a/e2e/interface.go
+++ b/e2e/interface.go
@@ -1,7 +1,15 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package e2e
 
 import (
 	"gitlab.com/elixxir/client/cmix/rounds"
+	"gitlab.com/elixxir/crypto/e2e"
 	"time"
 
 	"github.com/cloudflare/circl/dh/sidh"
@@ -12,7 +20,6 @@ import (
 	"gitlab.com/elixxir/client/e2e/receive"
 	"gitlab.com/elixxir/client/stoppable"
 	"gitlab.com/elixxir/crypto/cyclic"
-	"gitlab.com/elixxir/crypto/e2e"
 	"gitlab.com/xx_network/primitives/id"
 )
 
@@ -35,7 +42,7 @@ type Handler interface {
 	// Will return an error if the network is not healthy or in
 	// the event of a failed send
 	SendE2E(mt catalog.MessageType, recipient *id.ID, payload []byte,
-		params Params) ([]id.Round, e2e.MessageID, time.Time, error)
+		params Params) (e2e.SendReport, error)
 
 	/* === Reception ==================================================== */
 
diff --git a/e2e/legacyGen_test.go b/e2e/legacyGen_test.go
index 80b5da30fbcad3bb93651e29568f2a089a4fd364..836d750f675b51a22b523bb412391c312509bf59 100644
--- a/e2e/legacyGen_test.go
+++ b/e2e/legacyGen_test.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package e2e
 
 // legacyGen_test.go contains the code for generating e2e relationships
diff --git a/e2e/manager.go b/e2e/manager.go
index bd7c313811a792ddc5535f8e4ab0f00cd97406b0..72197eb40c645bbc4e55a5d7485fcab4240203f4 100644
--- a/e2e/manager.go
+++ b/e2e/manager.go
@@ -1,13 +1,19 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package e2e
 
 import (
 	"bytes"
 	"encoding/base64"
 	"encoding/json"
-	"sync"
-	"time"
-
 	jww "github.com/spf13/jwalterweatherman"
+	"gitlab.com/elixxir/crypto/e2e"
+	"sync"
 
 	"gitlab.com/xx_network/primitives/netTime"
 
@@ -23,7 +29,6 @@ import (
 	"gitlab.com/elixxir/client/stoppable"
 	"gitlab.com/elixxir/client/storage/versioned"
 	"gitlab.com/elixxir/crypto/cyclic"
-	"gitlab.com/elixxir/crypto/e2e"
 	"gitlab.com/elixxir/crypto/fastRNG"
 	"gitlab.com/xx_network/primitives/id"
 )
@@ -70,7 +75,7 @@ func initE2E(kv *versioned.KV, myID *id.ID, privKey *cyclic.Int,
 	if err != nil {
 		return errors.WithMessage(err, "Failed to marshal rekeyParams")
 	}
-	err = kv.Set(e2eRekeyParamsKey, e2eRekeyParamsVer, &versioned.Object{
+	err = kv.Set(e2eRekeyParamsKey, &versioned.Object{
 		Version:   e2eRekeyParamsVer,
 		Timestamp: netTime.Now(),
 		Data:      rekeyParamsData,
@@ -123,7 +128,7 @@ func LoadLegacy(kv *versioned.KV, net cmix.Client, myID *id.ID,
 	}
 
 	// Store the rekey params to disk/memory
-	err = kv.Set(e2eRekeyParamsKey, e2eRekeyParamsVer, &versioned.Object{
+	err = kv.Set(e2eRekeyParamsKey, &versioned.Object{
 		Version:   e2eRekeyParamsVer,
 		Timestamp: netTime.Now(),
 		Data:      rekeyParamsData,
@@ -131,7 +136,7 @@ func LoadLegacy(kv *versioned.KV, net cmix.Client, myID *id.ID,
 	if err != nil {
 		return nil, err
 	}
-	err = kv.Set(legacyE2EKey, e2eRekeyParamsVer, &versioned.Object{
+	err = kv.Set(legacyE2EKey, &versioned.Object{
 		Version:   e2eRekeyParamsVer,
 		Timestamp: netTime.Now(),
 		Data:      []byte{1},
@@ -214,8 +219,7 @@ func (m *manager) StartProcesses() (stoppable.Stoppable, error) {
 
 	rekeySendFunc := func(mt catalog.MessageType,
 		recipient *id.ID, payload []byte,
-		cmixParams cmix.CMIXParams) (
-		[]id.Round, e2e.MessageID, time.Time, error) {
+		cmixParams cmix.CMIXParams) (e2e.SendReport, error) {
 		// FIXME: we should have access to the e2e params here...
 		par := GetDefaultParams()
 		par.CMIXParams = cmixParams
@@ -284,14 +288,15 @@ func (m *manager) DeletePartnerNotify(partnerId *id.ID, params Params) error {
 	m.DeletePartnerCallbacks(partnerId)
 
 	// Send closing E2E message
-	rounds, msgID, timestamp, err := sendFunc()
+
+	sendReport, err := sendFunc()
 	if err != nil {
 		jww.ERROR.Printf("Failed to send %s E2E message to %s: %+v",
 			catalog.E2eClose, partnerId, err)
 	} else {
 		jww.INFO.Printf(
 			"Sent %s E2E message to %s on rounds %v with message ID %s at %s",
-			catalog.E2eClose, partnerId, rounds, msgID, timestamp)
+			catalog.E2eClose, partnerId, sendReport.RoundList, sendReport.MessageId, sendReport.SentTime)
 	}
 
 	return nil
diff --git a/e2e/manager_test.go b/e2e/manager_test.go
index 55fe430796c406a95b7f6a89268a29caa51bf6ff..46bd718658c97466b19f7a671eebcc9f7122d63b 100644
--- a/e2e/manager_test.go
+++ b/e2e/manager_test.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package e2e
 
 import (
diff --git a/e2e/params.go b/e2e/params.go
index 2702d490656342e975883177b115f63dbf2df961..1e5cbcb5f852740fc20ce1e38268e6cb700bd3d4 100644
--- a/e2e/params.go
+++ b/e2e/params.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package e2e
 
 import (
@@ -100,3 +107,9 @@ func (p *Params) UnmarshalJSON(data []byte) error {
 
 	return nil
 }
+
+// String implements stringer interface by returning a json string
+func (p *Params) String() string {
+	json, _ := p.MarshalJSON()
+	return string(json)
+}
diff --git a/e2e/parse/conversation/message.go b/e2e/parse/conversation/message.go
index bc7f92aa3f4bee6b2decd98a85f19e0c020be16e..82a6770827e6fc12b91c44f7c54d323b1fee84f4 100644
--- a/e2e/parse/conversation/message.go
+++ b/e2e/parse/conversation/message.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package conversation
 
diff --git a/e2e/parse/conversation/message_test.go b/e2e/parse/conversation/message_test.go
index 35cc9403604caeb40f4932cee3ed52a058520945..6c220fd9b789835d4ac83a66188efc5a9dd282d5 100644
--- a/e2e/parse/conversation/message_test.go
+++ b/e2e/parse/conversation/message_test.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package conversation
 
diff --git a/e2e/parse/conversation/partner.go b/e2e/parse/conversation/partner.go
index 06155c697b6674c16261cb84af74ccb714feb69c..03158a059eb85b8e27c30ae3302740e2f239bdfd 100644
--- a/e2e/parse/conversation/partner.go
+++ b/e2e/parse/conversation/partner.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package conversation
 
@@ -14,9 +14,7 @@ import (
 	"gitlab.com/elixxir/client/storage/versioned"
 	"gitlab.com/xx_network/primitives/id"
 	"gitlab.com/xx_network/primitives/netTime"
-	"io/fs"
 	"math"
-	"strings"
 	"sync"
 )
 
@@ -51,7 +49,7 @@ type conversationDisk struct {
 // saved to KV, and returned.
 func LoadOrMakeConversation(kv *versioned.KV, partner *id.ID) *Conversation {
 	c, err := loadConversation(kv, partner)
-	if err != nil && !(errors.Is(err, fs.ErrNotExist) || strings.Contains(err.Error(), "object not found")) {
+	if err != nil && kv.Exists(err) {
 		jww.FATAL.Panicf("Failed to load conversation from storage: %+v", err)
 	} else if c == nil {
 		// Create new conversation and save to KV if one does not exist
@@ -163,7 +161,7 @@ func (c *Conversation) save() error {
 	}
 
 	key := makeConversationKey(c.partner)
-	return c.kv.Set(key, currentConversationVersion, &obj)
+	return c.kv.Set(key, &obj)
 }
 
 // delete removes the Conversation from KV storage.
diff --git a/e2e/parse/conversation/partner_test.go b/e2e/parse/conversation/partner_test.go
index 41dd638ca5a04fefc125c2a4977715c5c4493f5c..0d7e9883c30bee788126abb67d3b591007427902 100644
--- a/e2e/parse/conversation/partner_test.go
+++ b/e2e/parse/conversation/partner_test.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package conversation
 
diff --git a/e2e/parse/conversation/ring.go b/e2e/parse/conversation/ring.go
index 7e255451bae9eae4fbada051fc85ea4a1bb4067f..88304e97c61662af209edf81a64de540236b569c 100644
--- a/e2e/parse/conversation/ring.go
+++ b/e2e/parse/conversation/ring.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package conversation
 
@@ -231,7 +231,7 @@ func (b *Buff) saveBuff() error {
 		Data:      b.marshal(),
 	}
 
-	return b.kv.Set(ringBuffKey, ringBuffVersion, obj)
+	return b.kv.Set(ringBuffKey, obj)
 }
 
 // marshal creates a byte buffer containing serialized information on the Buff.
@@ -293,7 +293,7 @@ func (b *Buff) saveMessage(msg *Message) error {
 	}
 
 	return b.kv.Set(
-		makeMessageKey(msg.MessageId.truncate()), messageVersion, obj)
+		makeMessageKey(msg.MessageId.truncate()), obj)
 
 }
 
diff --git a/e2e/parse/conversation/ring_test.go b/e2e/parse/conversation/ring_test.go
index 1d1db1983fbe265d6841b22c1f969b21119806f7..fd70ef07fa260e68edd7ac8c28fde2ded6ce2e41 100644
--- a/e2e/parse/conversation/ring_test.go
+++ b/e2e/parse/conversation/ring_test.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package conversation
 
diff --git a/e2e/parse/conversation/store.go b/e2e/parse/conversation/store.go
index 288e87674fa1cd6789bdacc538052cbc2173ae57..b1fc1f08e8deb91bae8ef1d2ddb1392daa60dfe6 100644
--- a/e2e/parse/conversation/store.go
+++ b/e2e/parse/conversation/store.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package conversation
 
diff --git a/e2e/parse/conversation/store_test.go b/e2e/parse/conversation/store_test.go
index 176d251be7085dba1baa22e9038aeef10efb58fc..b7f8ab5f5a00d4e912ce13256a1cce3952b67d1f 100644
--- a/e2e/parse/conversation/store_test.go
+++ b/e2e/parse/conversation/store_test.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package conversation
 
diff --git a/e2e/parse/firstMessagePart.go b/e2e/parse/firstMessagePart.go
index ae907af3d2b921f69a3770f1ad0aa8e1da72541d..f44007ad32ee2190ee75a2572082d120ea6bedae 100644
--- a/e2e/parse/firstMessagePart.go
+++ b/e2e/parse/firstMessagePart.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package parse
 
diff --git a/e2e/parse/firstMessagePart_test.go b/e2e/parse/firstMessagePart_test.go
index cfe419be245d7f73e730ba142a827daf3ebac942..9d895ee89aff09bdd552df7c61613a6257ee1f7c 100644
--- a/e2e/parse/firstMessagePart_test.go
+++ b/e2e/parse/firstMessagePart_test.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package parse
 
diff --git a/e2e/parse/messagePart.go b/e2e/parse/messagePart.go
index b1c3a9dfe2d4ef65ca247d8f940db165d5679070..e5908cf117c9079bde3a99f04b88eec229d4a356 100644
--- a/e2e/parse/messagePart.go
+++ b/e2e/parse/messagePart.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package parse
 
diff --git a/e2e/parse/messagePart_test.go b/e2e/parse/messagePart_test.go
index adede5571164836de7c493f045767f03315eea9a..837765d7ab3f53c201af6725c2ae16a78e2865e3 100644
--- a/e2e/parse/messagePart_test.go
+++ b/e2e/parse/messagePart_test.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package parse
 
diff --git a/e2e/parse/partition.go b/e2e/parse/partition.go
index da7628381175971f748d456761ccc836345bd227..b951df9f6f3e5f8d54b80e16a04484249afb3821 100644
--- a/e2e/parse/partition.go
+++ b/e2e/parse/partition.go
@@ -1,13 +1,14 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package parse
 
 import (
+	"gitlab.com/elixxir/crypto/e2e"
 	"time"
 
 	"github.com/pkg/errors"
@@ -78,7 +79,8 @@ func (p *Partitioner) Partition(recipient *id.ID, mt catalog.MessageType,
 }
 
 func (p *Partitioner) HandlePartition(sender *id.ID,
-	contents []byte, relationshipFingerprint []byte) (receive.Message, bool) {
+	contents []byte, relationshipFingerprint []byte,
+	residue e2e.KeyResidue) (receive.Message, e2e.KeyResidue, bool) {
 
 	if isFirst(contents) {
 		// If it is the first message in a set, then handle it as so
@@ -92,7 +94,7 @@ func (p *Partitioner) HandlePartition(sender *id.ID,
 		storageTimestamp := netTime.Now()
 		return p.partition.AddFirst(sender, fm.getType(), messageID,
 			fm.getPart(), fm.getNumParts(), fm.getTimestamp(), storageTimestamp,
-			fm.getSizedContents(), relationshipFingerprint)
+			fm.getSizedContents(), relationshipFingerprint, residue)
 	} else {
 		// If it is a subsequent message part, handle it as so
 		mp := messagePartFromBytes(contents)
diff --git a/e2e/parse/partition/multiPartMessage.go b/e2e/parse/partition/multiPartMessage.go
index d067248d2a792fe846a9cb2e42c92ba001d5b3d5..e716cdbc2f6180e5cfc464e6ca432eb64f276d67 100644
--- a/e2e/parse/partition/multiPartMessage.go
+++ b/e2e/parse/partition/multiPartMessage.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package partition
 
@@ -15,7 +15,6 @@ import (
 	"gitlab.com/elixxir/client/e2e/receive"
 	"gitlab.com/elixxir/client/storage/versioned"
 	"gitlab.com/elixxir/crypto/e2e"
-	"gitlab.com/elixxir/ekv"
 	"gitlab.com/xx_network/primitives/id"
 	"gitlab.com/xx_network/primitives/netTime"
 	"strconv"
@@ -41,6 +40,8 @@ type multiPartMessage struct {
 	StorageTimestamp time.Time
 	MessageType      catalog.MessageType
 
+	KeyResidue e2e.KeyResidue
+
 	parts [][]byte
 	kv    *versioned.KV
 	mux   sync.Mutex
@@ -55,7 +56,7 @@ func loadOrCreateMultiPartMessage(sender *id.ID, messageID uint64,
 
 	obj, err := kv.Get(messageKey, currentMultiPartMessageVersion)
 	if err != nil {
-		if !ekv.Exists(err) {
+		if !kv.Exists(err) {
 			mpm := &multiPartMessage{
 				Sender:          sender,
 				MessageID:       messageID,
@@ -100,7 +101,7 @@ func (mpm *multiPartMessage) save() error {
 		Data:      data,
 	}
 
-	return mpm.kv.Set(messageKey, currentMultiPartMessageVersion, &obj)
+	return mpm.kv.Set(messageKey, &obj)
 }
 
 func (mpm *multiPartMessage) Add(partNumber uint8, part []byte) {
diff --git a/e2e/parse/partition/multiPartMessage_test.go b/e2e/parse/partition/multiPartMessage_test.go
index 616b7dda8d3bcae9799b78ac595f4a6fe3f123ad..2a2da3064140e123cb9f7305a4d1cf8fdd0b1fbd 100644
--- a/e2e/parse/partition/multiPartMessage_test.go
+++ b/e2e/parse/partition/multiPartMessage_test.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package partition
 
@@ -264,7 +264,7 @@ func TestMultiPartMessage_delete(t *testing.T) {
 
 	mpm.delete()
 	obj, err := kv.Get(messageKey, 0)
-	if ekv.Exists(err) {
+	if kv.Exists(err) {
 		t.Errorf("delete did not properly delete key %s."+
 			"\n\tobject received: %+v", messageKey, obj)
 	}
diff --git a/e2e/parse/partition/part.go b/e2e/parse/partition/part.go
index 25b0e2566abe28ef39d5605ab1cdc90d5f2542f9..78b3a8e4b337d98657fba68273de01f57f7b04d1 100644
--- a/e2e/parse/partition/part.go
+++ b/e2e/parse/partition/part.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package partition
 
@@ -30,12 +30,11 @@ func savePart(kv *versioned.KV, partNum uint8, part []byte) error {
 	key := makeMultiPartMessagePartKey(partNum)
 
 	obj := versioned.Object{
-		Version:   currentMultiPartMessagePartVersion,
+		Version:   currentMultiPartMessageVersion,
 		Timestamp: netTime.Now(),
 		Data:      part,
 	}
-
-	return kv.Set(key, currentMultiPartMessageVersion, &obj)
+	return kv.Set(key, &obj)
 }
 
 func deletePart(kv *versioned.KV, partNum uint8) error {
diff --git a/e2e/parse/partition/part_test.go b/e2e/parse/partition/part_test.go
index 53366fdb6d211a74e531e21cf8b4f0a9665079c3..9556771c022bc9615948d082c9e369a49f1596be 100644
--- a/e2e/parse/partition/part_test.go
+++ b/e2e/parse/partition/part_test.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package partition
 
@@ -57,7 +57,7 @@ func Test_loadPart(t *testing.T) {
 
 	// Save part to key value store
 	err := rootKv.Set(
-		key, 0, &versioned.Object{Timestamp: netTime.Now(), Data: part})
+		key, &versioned.Object{Timestamp: netTime.Now(), Data: part})
 	if err != nil {
 		t.Errorf("Failed to set object: %+v", err)
 	}
@@ -87,7 +87,7 @@ func Test_loadPart_NotFoundError(t *testing.T) {
 
 	// Load part from key value store
 	data, err := loadPart(kv, partNum)
-	if ekv.Exists(err) {
+	if kv.Exists(err) {
 		t.Errorf("loadPart found an item for the key: %v", err)
 	}
 
@@ -121,7 +121,7 @@ func TestDeletePart(t *testing.T) {
 
 	// Check if part was deleted
 	_, err = loadPart(kv, partNum)
-	if ekv.Exists(err) {
+	if kv.Exists(err) {
 		t.Errorf("part was found in key value store: %+v", err)
 	}
 }
diff --git a/e2e/parse/partition/store.go b/e2e/parse/partition/store.go
index 7774e3187b90235d79f2ce4082024e8f4a547dec..713fc291a9bb530994c3598b26e595eea52a6b03 100644
--- a/e2e/parse/partition/store.go
+++ b/e2e/parse/partition/store.go
@@ -1,19 +1,21 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package partition
 
 import (
+	"bytes"
 	"encoding/binary"
 	"encoding/json"
 	jww "github.com/spf13/jwalterweatherman"
 	"gitlab.com/elixxir/client/catalog"
 	"gitlab.com/elixxir/client/e2e/receive"
 	"gitlab.com/elixxir/client/storage/versioned"
+	"gitlab.com/elixxir/crypto/e2e"
 	"gitlab.com/xx_network/primitives/id"
 	"gitlab.com/xx_network/primitives/netTime"
 	"golang.org/x/crypto/blake2b"
@@ -49,47 +51,60 @@ func NewOrLoad(kv *versioned.KV) *Store {
 	return partitionStore
 }
 
+// AddFirst adds the first partition message to the Store object.
 func (s *Store) AddFirst(partner *id.ID, mt catalog.MessageType,
 	messageID uint64, partNum, numParts uint8, senderTimestamp,
-	storageTimestamp time.Time, part []byte, relationshipFingerprint []byte) (
-	receive.Message, bool) {
+	storageTimestamp time.Time, part []byte, relationshipFingerprint []byte,
+	residue e2e.KeyResidue) (
+	receive.Message, e2e.KeyResidue, bool) {
 
 	mpm := s.load(partner, messageID)
-
 	mpm.AddFirst(mt, partNum, numParts, senderTimestamp, storageTimestamp, part)
+	if bytes.Equal(residue.Marshal(), []byte{}) {
+		// fixme: should this error or crash?
+		jww.WARN.Printf("Key reside from first message " +
+			"is empty, continuing...")
+	}
+
+	mpm.KeyResidue = residue
 	msg, ok := mpm.IsComplete(relationshipFingerprint)
 
 	s.mux.Lock()
 	defer s.mux.Unlock()
 
+	keyRes := e2e.KeyResidue{}
 	if !ok {
 		s.activeParts[mpm] = true
 		s.saveActiveParts()
 	} else {
+		keyRes = mpm.KeyResidue
 		mpID := getMultiPartID(mpm.Sender, mpm.MessageID)
 		delete(s.multiParts, mpID)
 	}
 
-	return msg, ok
+	return msg, keyRes, ok
 }
 
 func (s *Store) Add(partner *id.ID, messageID uint64, partNum uint8,
-	part []byte, relationshipFingerprint []byte) (receive.Message, bool) {
+	part []byte, relationshipFingerprint []byte) (
+	receive.Message, e2e.KeyResidue, bool) {
 
 	mpm := s.load(partner, messageID)
 
 	mpm.Add(partNum, part)
 
 	msg, ok := mpm.IsComplete(relationshipFingerprint)
+	keyRes := e2e.KeyResidue{}
 	if !ok {
 		s.activeParts[mpm] = true
 		s.saveActiveParts()
 	} else {
+		keyRes = mpm.KeyResidue
 		mpID := getMultiPartID(mpm.Sender, mpm.MessageID)
 		delete(s.multiParts, mpID)
 	}
 
-	return msg, ok
+	return msg, keyRes, ok
 }
 
 // prune clears old messages on it's stored timestamp.
@@ -145,7 +160,7 @@ func (s *Store) saveActiveParts() {
 		Data:      data,
 	}
 
-	err = s.kv.Set(activePartitions, activePartitionVersion, &obj)
+	err = s.kv.Set(activePartitions, &obj)
 	if err != nil {
 		jww.FATAL.Panicf("Could not save active partitions: %+v", err)
 	}
@@ -156,7 +171,7 @@ func (s *Store) loadActivePartitions() {
 	defer s.mux.Unlock()
 	obj, err := s.kv.Get(activePartitions, activePartitionVersion)
 	if err != nil {
-		jww.DEBUG.Printf("Could not load active partitions: %+v", err)
+		jww.DEBUG.Printf("Could not load active partitions: %s", err.Error())
 		return
 	}
 
diff --git a/e2e/parse/partition/store_test.go b/e2e/parse/partition/store_test.go
index 909de9b829d54e7b07fc4936ed82bdd2337ccc5f..9ef6fcfd1b2a847e8d17aec4064923630fb57496 100644
--- a/e2e/parse/partition/store_test.go
+++ b/e2e/parse/partition/store_test.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package partition
 
@@ -11,6 +11,7 @@ import (
 	"bytes"
 	"gitlab.com/elixxir/client/catalog"
 	"gitlab.com/elixxir/client/storage/versioned"
+	"gitlab.com/elixxir/crypto/e2e"
 	"gitlab.com/elixxir/ekv"
 	"gitlab.com/xx_network/primitives/id"
 	"gitlab.com/xx_network/primitives/netTime"
@@ -39,15 +40,27 @@ func TestNewOrLoad(t *testing.T) {
 func TestStore_AddFirst(t *testing.T) {
 	part := []byte("Test message.")
 	s := NewOrLoad(versioned.NewKV(ekv.MakeMemstore()))
+	b := make([]byte, e2e.KeyResidueLength)
+	kr, err := e2e.UnmarshalKeyResidue(b)
+	if err != nil {
+		t.Fatalf("Failed to unmarshal key residue: %+v", err)
+	}
 
-	msg, complete := s.AddFirst(id.NewIdFromString("User", id.User, t),
+	msg, receivedKr, complete := s.AddFirst(id.NewIdFromString("User", id.User, t),
 		catalog.XxMessage, 5, 0, 1, netTime.Now(), netTime.Now(), part,
-		[]byte{0})
+		[]byte{0}, kr)
 
 	if !complete {
 		t.Errorf("AddFirst returned that the message was not complete.")
 	}
 
+	if !bytes.Equal(receivedKr[:], kr[:]) {
+		t.Fatalf("Key residue returned from complete partition did not "+
+			"match first key signature."+
+			"\nExpected: %v"+
+			"\nReceived: %v", kr, receivedKr)
+	}
+
 	if !bytes.Equal(part, msg.Payload) {
 		t.Errorf("AddFirst returned message with invalid payload."+
 			"\nexpected: %v\nreceived: %v", part, msg.Payload)
@@ -59,21 +72,33 @@ func TestStore_Add(t *testing.T) {
 	part1 := []byte("Test message.")
 	part2 := []byte("Second Sentence.")
 	s := NewOrLoad(versioned.NewKV(ekv.MakeMemstore()))
+	b := make([]byte, e2e.KeyResidueLength)
+	kr, err := e2e.UnmarshalKeyResidue(b)
+	if err != nil {
+		t.Fatalf("Failed to unmarshal key residue: %+v", err)
+	}
 
-	msg, complete := s.AddFirst(id.NewIdFromString("User", id.User, t),
+	msg, _, complete := s.AddFirst(id.NewIdFromString("User", id.User, t),
 		catalog.XxMessage, 5, 0, 2, netTime.Now(), netTime.Now(), part1,
-		[]byte{0})
+		[]byte{0}, kr)
 
 	if complete {
 		t.Errorf("AddFirst returned that the message was complete.")
 	}
 
-	msg, complete = s.Add(id.NewIdFromString("User", id.User, t),
+	msg, receivedKr, complete := s.Add(id.NewIdFromString("User", id.User, t),
 		5, 1, part2, []byte{0})
 	if !complete {
 		t.Errorf("AddFirst returned that the message was not complete.")
 	}
 
+	if !bytes.Equal(receivedKr[:], kr[:]) {
+		t.Fatalf("Key residue returned from complete partition did not "+
+			"match first key signature."+
+			"\nExpected: %v"+
+			"\nReceived: %v", kr, receivedKr)
+	}
+
 	part := append(part1, part2...)
 	if !bytes.Equal(part, msg.Payload) {
 		t.Errorf("AddFirst returned message with invalid payload."+
@@ -92,10 +117,15 @@ func TestStore_prune(t *testing.T) {
 	partner1 := id.NewIdFromString("User", id.User, t)
 	messageId1 := uint64(5)
 	oldTimestamp := netTime.Now().Add(-2 * clearPartitionThreshold)
+	b := make([]byte, e2e.KeyResidueLength)
+	kr, err := e2e.UnmarshalKeyResidue(b)
+	if err != nil {
+		t.Fatalf("Failed to unmarshal key residue: %+v", err)
+	}
 	s.AddFirst(partner1,
 		catalog.XxMessage, messageId1, 0, 2, netTime.Now(),
 		oldTimestamp, part1,
-		[]byte{0})
+		[]byte{0}, kr)
 	s.Add(partner1, messageId1, 1, part2, []byte{0})
 
 	partner2 := id.NewIdFromString("User1", id.User, t)
@@ -103,7 +133,7 @@ func TestStore_prune(t *testing.T) {
 	newTimestamp := netTime.Now()
 	s.AddFirst(partner2, catalog.XxMessage, messageId2, 0, 2, netTime.Now(),
 		newTimestamp, part1,
-		[]byte{0})
+		[]byte{0}, kr)
 
 	// Call clear messages
 	s.prune()
diff --git a/e2e/parse/partition_test.go b/e2e/parse/partition_test.go
index 22c1f238eda4b2f2f0be5575e68143c28970a749..2f1c41418805b0f6f31d267023c4b602802c04d4 100644
--- a/e2e/parse/partition_test.go
+++ b/e2e/parse/partition_test.go
@@ -1,13 +1,14 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package parse
 
 import (
+	"gitlab.com/elixxir/crypto/e2e"
 	"testing"
 
 	"gitlab.com/elixxir/client/catalog"
@@ -72,10 +73,11 @@ func TestPartitioner_HandlePartition(t *testing.T) {
 	p := NewPartitioner(versioned.NewKV(ekv.MakeMemstore()), len(ipsumTestStr))
 	m := newMessagePart(1107, 1, []byte(ipsumTestStr), len(ipsumTestStr)+headerLen)
 
-	_, _ = p.HandlePartition(
+	_, _, _ = p.HandlePartition(
 		&id.DummyUser,
 		m.bytes(),
 		[]byte{'t', 'e', 's', 't', 'i', 'n', 'g', 's', 't', 'r', 'i', 'n', 'g'},
+		e2e.KeyResidue{},
 	)
 }
 
@@ -85,9 +87,10 @@ func TestPartitioner_HandleFirstPartition(t *testing.T) {
 	m := newFirstMessagePart(
 		catalog.XxMessage, 1107, 1, netTime.Now(), []byte(ipsumTestStr), len([]byte(ipsumTestStr))+firstHeaderLen)
 
-	_, _ = p.HandlePartition(
+	_, _, _ = p.HandlePartition(
 		&id.DummyUser,
 		m.bytes(),
 		[]byte{'t', 'e', 's', 't', 'i', 'n', 'g', 's', 't', 'r', 'i', 'n', 'g'},
+		e2e.KeyResidue{},
 	)
 }
diff --git a/e2e/processor.go b/e2e/processor.go
index 17e2293401209f84783f4855182f607cc8f6bd0e..86673f81f235b905eaae31df7a2e786415584f3b 100644
--- a/e2e/processor.go
+++ b/e2e/processor.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package e2e
 
 import (
@@ -23,7 +30,7 @@ func (p *processor) Process(ecrMsg format.Message,
 	// ensure the key will be marked used before returning
 	defer p.cy.Use()
 
-	contents, err := p.cy.Decrypt(ecrMsg)
+	contents, residue, err := p.cy.Decrypt(ecrMsg)
 	if err != nil {
 		jww.ERROR.Printf("decrypt failed of %s (fp: %s), dropping: %+v",
 			ecrMsg.Digest(), p.cy.Fingerprint(), err)
@@ -31,8 +38,9 @@ func (p *processor) Process(ecrMsg format.Message,
 	}
 
 	sess := p.cy.GetSession()
-	message, done := p.m.partitioner.HandlePartition(sess.GetPartner(),
-		contents, sess.GetRelationshipFingerprint())
+	// todo: handle residue here
+	message, _, done := p.m.partitioner.HandlePartition(sess.GetPartner(),
+		contents, sess.GetRelationshipFingerprint(), residue)
 	if done {
 		message.RecipientID = receptionID.Source
 		message.EphemeralID = receptionID.EphId
diff --git a/e2e/ratchet/partner/interface.go b/e2e/ratchet/partner/interface.go
index 1074893e8ead14f8280133bd59a5276723b69339..c0fa978410da820c2b3f7d800bd2525375b913d3 100644
--- a/e2e/ratchet/partner/interface.go
+++ b/e2e/ratchet/partner/interface.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package partner
 
 import (
diff --git a/e2e/ratchet/partner/manager.go b/e2e/ratchet/partner/manager.go
index ec7799363f2a107da4a49d42f8b2404d0dc0ac85..42169477dc2a5749c14de2e102f36b37f54eb40e 100644
--- a/e2e/ratchet/partner/manager.go
+++ b/e2e/ratchet/partner/manager.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package partner
 
diff --git a/e2e/ratchet/partner/manager_test.go b/e2e/ratchet/partner/manager_test.go
index dab364dec3727cc926d2aa1cabb46e5c445cc330..78ae006db5251246110e90892d2694a712ad6df6 100644
--- a/e2e/ratchet/partner/manager_test.go
+++ b/e2e/ratchet/partner/manager_test.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package partner
 
diff --git a/e2e/ratchet/partner/relationship.go b/e2e/ratchet/partner/relationship.go
index bd6f60ccef05edaaa526a01288b7905f4e351829..c7eb260f78f79f22847a45e653e0110873caeeb6 100644
--- a/e2e/ratchet/partner/relationship.go
+++ b/e2e/ratchet/partner/relationship.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package partner
 
@@ -161,7 +161,7 @@ func (r *relationship) save() error {
 		Data:      data,
 	}
 
-	return r.kv.Set(relationshipKey, currentRelationshipVersion, &obj)
+	return r.kv.Set(relationshipKey, &obj)
 }
 
 //ekv functions
diff --git a/e2e/ratchet/partner/relationshipFingerprint.go b/e2e/ratchet/partner/relationshipFingerprint.go
index 9380b9a5051e9d82f76d3043e880350600425d6b..3bad30633b9556df8e5fe0e4ba97a07dc5254089 100644
--- a/e2e/ratchet/partner/relationshipFingerprint.go
+++ b/e2e/ratchet/partner/relationshipFingerprint.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package partner
 
@@ -40,13 +40,12 @@ func makeRelationshipFingerprint(t session2.RelationshipType, grp *cyclic.Group,
 func storeRelationshipFingerprint(fp []byte, kv *versioned.KV) error {
 	now := netTime.Now()
 	obj := versioned.Object{
-		Version:   currentRelationshipFingerprintVersion,
+		Version:   currentRelationshipVersion,
 		Timestamp: now,
 		Data:      fp,
 	}
 
-	return kv.Set(relationshipFingerprintKey, currentRelationshipVersion,
-		&obj)
+	return kv.Set(relationshipFingerprintKey, &obj)
 }
 
 func loadRelationshipFingerprint(kv *versioned.KV) []byte {
diff --git a/e2e/ratchet/partner/relationship_test.go b/e2e/ratchet/partner/relationship_test.go
index 5160844daf0c6c3dcc6e4ea2844065f42f2b612b..3df242bcbfeb5612412420746177bc234471fd13 100644
--- a/e2e/ratchet/partner/relationship_test.go
+++ b/e2e/ratchet/partner/relationship_test.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package partner
 
diff --git a/e2e/ratchet/partner/session/cypher.go b/e2e/ratchet/partner/session/cypher.go
index ef4094a40f0967f199dd4f89786fd6a2dcda5459..1a607a290fdd476a940dc77cbc89683e9387fb69 100644
--- a/e2e/ratchet/partner/session/cypher.go
+++ b/e2e/ratchet/partner/session/cypher.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package session
 
@@ -63,13 +63,15 @@ type Cypher interface {
 
 	// Encrypt uses the E2E key to encrypt the message to its intended
 	// recipient. It also properly populates the associated data, including the
-	// MAC, fingerprint, and encrypted timestamp.
-	Encrypt(contents []byte) (ecrContents, mac []byte)
+	// MAC, fingerprint, and encrypted timestamp. It generates a residue of the
+	// key used to encrypt the contents.
+	Encrypt(contents []byte) (ecrContents, mac []byte, residue e2eCrypto.KeyResidue)
 
 	// Decrypt uses the E2E key to decrypt the message. It returns an error in
 	// case of HMAC verification failure or in case of a decryption error
-	// (related to padding).
-	Decrypt(msg format.Message) ([]byte, error)
+	// (related to padding). It generates a residue of the
+	// key used to encrypt the contents.
+	Decrypt(msg format.Message) (decryptedPayload []byte, residue e2eCrypto.KeyResidue, err error)
 
 	// Use sets the key as used. It cannot be used again.
 	Use()
@@ -110,11 +112,13 @@ func (k *cypher) Fingerprint() format.Fingerprint {
 
 // Encrypt uses the E2E key to encrypt the message to its intended recipient. It
 // also properly populates the associated data, including the MAC, fingerprint,
-// and encrypted timestamp.
-func (k *cypher) Encrypt(contents []byte) (ecrContents, mac []byte) {
+// and encrypted timestamp. It generates a residue of the key used to encrypt the contents.
+func (k *cypher) Encrypt(contents []byte) (ecrContents, mac []byte, residue e2eCrypto.KeyResidue) {
 	fp := k.Fingerprint()
 	key := k.generateKey()
 
+	residue = e2eCrypto.NewKeyResidue(key)
+
 	// encrypt the payload
 	ecrContents = e2eCrypto.Crypt(key, fp, contents)
 
@@ -122,25 +126,28 @@ func (k *cypher) Encrypt(contents []byte) (ecrContents, mac []byte) {
 	// Currently, the MAC doesn't include any of the associated data
 	mac = hash.CreateHMAC(ecrContents, key[:])
 
-	return ecrContents, mac
+	return ecrContents, mac, residue
 }
 
 // Decrypt uses the E2E key to decrypt the message. It returns an error in case
 // of HMAC verification failure or in case of a decryption error (related to
-// padding).
-func (k *cypher) Decrypt(msg format.Message) ([]byte, error) {
+// padding). It generates a residue of the key used to encrypt the contents
+func (k *cypher) Decrypt(msg format.Message) (decryptedPayload []byte, residue e2eCrypto.KeyResidue, err error) {
 	fp := k.Fingerprint()
 	key := k.generateKey()
 
 	// Verify the MAC is correct
 	if !hash.VerifyHMAC(msg.GetContents(), msg.GetMac(), key[:]) {
-		return nil, errors.New("HMAC verification failed for E2E message")
+		return nil, e2eCrypto.KeyResidue{}, errors.New("HMAC verification failed for E2E message")
 	}
 
 	// Decrypt the payload
-	decryptedPayload := e2eCrypto.Crypt(key, fp, msg.GetContents())
+	decryptedPayload = e2eCrypto.Crypt(key, fp, msg.GetContents())
+
+	// Construct residue
+	residue = e2eCrypto.NewKeyResidue(key)
 
-	return decryptedPayload, nil
+	return decryptedPayload, residue, nil
 }
 
 // Use sets the key as used. It cannot be used again.
diff --git a/e2e/ratchet/partner/session/cypherHandler.go b/e2e/ratchet/partner/session/cypherHandler.go
index 9bba56fec7c40ab1d0103cceb21aa0ab542d042a..d3124804aeb1d7cca17dea38897ab1dfa0d350c8 100644
--- a/e2e/ratchet/partner/session/cypherHandler.go
+++ b/e2e/ratchet/partner/session/cypherHandler.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package session
 
 type CypherHandler interface {
diff --git a/e2e/ratchet/partner/session/cypher_test.go b/e2e/ratchet/partner/session/cypher_test.go
index b6c92de98bc3dcaf1b6e18237df418ad246dbe5b..470d6f2174540c0fcbec0482be983e2425eb5f8d 100644
--- a/e2e/ratchet/partner/session/cypher_test.go
+++ b/e2e/ratchet/partner/session/cypher_test.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package session
 
@@ -153,7 +153,7 @@ func Test_cypher_EncryptDecrypt(t *testing.T) {
 		msg.SetContents(contents)
 
 		// Encrypt
-		contentsEnc, mac := cy.Encrypt(msg.GetContents())
+		contentsEnc, mac, _ := cy.Encrypt(msg.GetContents())
 
 		// Make the encrypted message
 		ecrMsg := format.NewMessage(grp.GetP().ByteLen())
@@ -162,7 +162,7 @@ func Test_cypher_EncryptDecrypt(t *testing.T) {
 		ecrMsg.SetMac(mac)
 
 		// Decrypt
-		contentsDecr, err := cy.Decrypt(ecrMsg)
+		contentsDecr, _, err := cy.Decrypt(ecrMsg)
 		if err != nil {
 			t.Fatalf("Decrypt error: %+v", err)
 		}
diff --git a/e2e/ratchet/partner/session/negotiation.go b/e2e/ratchet/partner/session/negotiation.go
index 267bf2d1e42804a34676abbbefb300c36655cecb..1f8b4ffec5043249e59d6d19cf2a0874fd7d4edc 100644
--- a/e2e/ratchet/partner/session/negotiation.go
+++ b/e2e/ratchet/partner/session/negotiation.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package session
 
diff --git a/e2e/ratchet/partner/session/params.go b/e2e/ratchet/partner/session/params.go
index 2782578e9e605d117d2bb872f40822816c0fde2f..47e103f6d9a4b375c357a40338a1230f87ed604d 100644
--- a/e2e/ratchet/partner/session/params.go
+++ b/e2e/ratchet/partner/session/params.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package session
 
 import (
diff --git a/e2e/ratchet/partner/session/relationshipType.go b/e2e/ratchet/partner/session/relationshipType.go
index cb2220ad40f01a6508184ac520dd980d7f0c4cf8..3545a55596c40758e37cc79bedf0d6e959c181d9 100644
--- a/e2e/ratchet/partner/session/relationshipType.go
+++ b/e2e/ratchet/partner/session/relationshipType.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package session
 
diff --git a/e2e/ratchet/partner/session/session.go b/e2e/ratchet/partner/session/session.go
index d0ee6ca19b1e233699ca6d7869e7e88420046b19..1ab3c1e771b64e2e5edd2d65aa0ace8a8abcbd89 100644
--- a/e2e/ratchet/partner/session/session.go
+++ b/e2e/ratchet/partner/session/session.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package session
 
@@ -239,7 +239,7 @@ func (s *Session) Save() error {
 
 	jww.WARN.Printf("saving with KV: %v", s.kv)
 
-	return s.kv.Set(sessionKey, currentSessionVersion, &obj)
+	return s.kv.Set(sessionKey, &obj)
 }
 
 /*METHODS*/
diff --git a/e2e/ratchet/partner/session/sessionID.go b/e2e/ratchet/partner/session/sessionID.go
index 82f0bf4f62699a8a53a2564282d837e32c825eaa..294c17e97e2d753e8074708bd79e7969826df195 100644
--- a/e2e/ratchet/partner/session/sessionID.go
+++ b/e2e/ratchet/partner/session/sessionID.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package session
 
diff --git a/e2e/ratchet/partner/session/session_test.go b/e2e/ratchet/partner/session/session_test.go
index cd72eee94c90ab559435e8dded5ecc0dbf346094..ed7e7d0b5ff09e4dcf9ba5e1c90e7531c6ff656f 100644
--- a/e2e/ratchet/partner/session/session_test.go
+++ b/e2e/ratchet/partner/session/session_test.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package session
 
diff --git a/e2e/ratchet/partner/session/status.go b/e2e/ratchet/partner/session/status.go
index 6494e31deafa043fa3bcf433fce5fea80cf772b4..294a0c9515550db475260bc9b5e75d06614a69e8 100644
--- a/e2e/ratchet/partner/session/status.go
+++ b/e2e/ratchet/partner/session/status.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package session
 
diff --git a/e2e/ratchet/partner/session/status_test.go b/e2e/ratchet/partner/session/status_test.go
index 738db5260e63c0396613a3543475e38a4edc8392..7fe85d11fc2dc80212cfa1dc363a5940d5d1d432 100644
--- a/e2e/ratchet/partner/session/status_test.go
+++ b/e2e/ratchet/partner/session/status_test.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package session
 
diff --git a/e2e/ratchet/partner/session/testUtils.go b/e2e/ratchet/partner/session/testUtils.go
index 61d82ea1f651820f0a9d76bcec396f094c820d4e..300d5e764d4fd8766fec9ee7c03d9bdb7ee73c1c 100644
--- a/e2e/ratchet/partner/session/testUtils.go
+++ b/e2e/ratchet/partner/session/testUtils.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package session
 
 import (
diff --git a/e2e/ratchet/partner/utils.go b/e2e/ratchet/partner/utils.go
index aa4c7d90e267848c50d53ce32ae87c63cb6febc9..ff0eef555cfda79fcc3fc8275375fb2e742f9388 100644
--- a/e2e/ratchet/partner/utils.go
+++ b/e2e/ratchet/partner/utils.go
@@ -1,13 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2022 Privategrity Corporation                                   /
-//                                                                             /
-// All rights reserved.                                                        /
-////////////////////////////////////////////////////////////////////////////////
-
-////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2022 Privategrity Corporation                                   /
-//                                                                             /
-// All rights reserved.                                                        /
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package partner
diff --git a/e2e/ratchet/partner/utils_test.go b/e2e/ratchet/partner/utils_test.go
index 17d28200b7c79868c7ca3f156b2d8f897b635e02..1aac1087aca130b60a0002da12f744f4cff2df6d 100644
--- a/e2e/ratchet/partner/utils_test.go
+++ b/e2e/ratchet/partner/utils_test.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package partner
 
 import (
diff --git a/e2e/ratchet/ratchet.go b/e2e/ratchet/ratchet.go
index 9995ba4eba11052ced441d53b897a1e310bccc60..b2421805ed9c3e0adac8971ed7959049589a735f 100644
--- a/e2e/ratchet/ratchet.go
+++ b/e2e/ratchet/ratchet.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package ratchet
 
diff --git a/e2e/ratchet/ratchet_test.go b/e2e/ratchet/ratchet_test.go
index a1cdbcb881b893dd5ebb4ce470078236e62b9f40..45f0c3ed822ec0d491dc3bf82fde5ce8f4f46619 100644
--- a/e2e/ratchet/ratchet_test.go
+++ b/e2e/ratchet/ratchet_test.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package ratchet
 
diff --git a/e2e/ratchet/serviceList.go b/e2e/ratchet/serviceList.go
index b382b5aced663ae8384b497052c29d57eb0ba71e..857a5be18218644bb58ec0d3746b8930daf76074 100644
--- a/e2e/ratchet/serviceList.go
+++ b/e2e/ratchet/serviceList.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package ratchet
 
 import (
diff --git a/e2e/ratchet/serviceList_test.go b/e2e/ratchet/serviceList_test.go
index 420d6c2756d43b1a468444005535852921b89ac1..522068190fa1a32fb023916517fdffd10f71c009 100644
--- a/e2e/ratchet/serviceList_test.go
+++ b/e2e/ratchet/serviceList_test.go
@@ -1,8 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package ratchet
diff --git a/e2e/ratchet/standardServices.go b/e2e/ratchet/standardServices.go
index 0d28c336b789e6ba182fcbb7c85a04fceed06f2e..21ed8cccd1399be95f9ec88bfb052f1cff1616be 100644
--- a/e2e/ratchet/standardServices.go
+++ b/e2e/ratchet/standardServices.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package ratchet
 
 const Silent = "silent"
diff --git a/e2e/ratchet/storage.go b/e2e/ratchet/storage.go
index 999938dc7ec1784743163acfd34a550a24134544..7db9c13a7c2ee1aa16e34ab55f70536f708230d4 100644
--- a/e2e/ratchet/storage.go
+++ b/e2e/ratchet/storage.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package ratchet
 
 import (
@@ -92,7 +99,7 @@ func (r *Ratchet) save() error {
 		Data:      data,
 	}
 
-	return r.kv.Set(storeKey, currentStoreVersion, &obj)
+	return r.kv.Set(storeKey, &obj)
 }
 
 // ekv functions
diff --git a/e2e/ratchet/utils_test.go b/e2e/ratchet/utils_test.go
index 27e735c9ed2c4b7b150b6c988884a79c1916407f..4444dd3a95df0f567c4239bd2f253e27633ff458 100644
--- a/e2e/ratchet/utils_test.go
+++ b/e2e/ratchet/utils_test.go
@@ -1,8 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package ratchet
diff --git a/e2e/receive/any.go b/e2e/receive/any.go
index fddafa55cdf6cfda3b679129c5ca9a26e2ded07d..e849ef5924b42e4963db0e034e77368a026d3cf1 100644
--- a/e2e/receive/any.go
+++ b/e2e/receive/any.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package receive
 
diff --git a/e2e/receive/any_test.go b/e2e/receive/any_test.go
index 9f554c1adc8faea4f410ac35ae5c3f41b89b7d8e..3cadcbffd7ec987140bcb52aa0f946abe15b46d1 100644
--- a/e2e/receive/any_test.go
+++ b/e2e/receive/any_test.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package receive
 
diff --git a/e2e/receive/byID.go b/e2e/receive/byID.go
index 425cd036e6b7c0bccc307621a709b08098b5ba2e..39b128d6fb5c5b792f4a9b0dd51d7e711659cfa4 100644
--- a/e2e/receive/byID.go
+++ b/e2e/receive/byID.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package receive
 
diff --git a/e2e/receive/byID_test.go b/e2e/receive/byID_test.go
index e8aebd2777242ff1e910876d0f2d964f493c3bc7..da58460a099e80f324f16096a176419abf55023c 100644
--- a/e2e/receive/byID_test.go
+++ b/e2e/receive/byID_test.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package receive
 
diff --git a/e2e/receive/byType.go b/e2e/receive/byType.go
index 183e2da360b5c03fceba294bcc578b6c73f6fb86..f43badcd32d6f0b58c00508b88e610af14243b0b 100644
--- a/e2e/receive/byType.go
+++ b/e2e/receive/byType.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package receive
 
diff --git a/e2e/receive/byType_test.go b/e2e/receive/byType_test.go
index 3ca6127d222f2b7b9038c7fbe7d2ac389c833969..140a7d2c3a99a558b7ee3a6744ae2ba260038e64 100644
--- a/e2e/receive/byType_test.go
+++ b/e2e/receive/byType_test.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package receive
 
diff --git a/e2e/receive/listener.go b/e2e/receive/listener.go
index 5e1d34067c5b7709509c18de6000103d73107687..e30365a9e6ce23a6608108f3ac2e0ae5809f5858 100644
--- a/e2e/receive/listener.go
+++ b/e2e/receive/listener.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package receive
 
diff --git a/e2e/receive/listener_test.go b/e2e/receive/listener_test.go
index e548ea7a488774b7b6be94182cda506a7484b23c..00b63beb6f00ab50314bba16b1a019d421af73c7 100644
--- a/e2e/receive/listener_test.go
+++ b/e2e/receive/listener_test.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package receive
 
diff --git a/e2e/receive/message.go b/e2e/receive/message.go
index 673b1e6ae0f8d2a72bdfc1ee6076f011a8b96088..bdde788c0cc6dba4304842e2adb29ce141a1013a 100644
--- a/e2e/receive/message.go
+++ b/e2e/receive/message.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package receive
 
 import (
diff --git a/e2e/receive/switchboard.go b/e2e/receive/switchboard.go
index 3f6122df73beeafd49129e1ab0d859e32e3a8ea5..99b6bf170ddfd57f125873b390ed91f17b7c906c 100644
--- a/e2e/receive/switchboard.go
+++ b/e2e/receive/switchboard.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package receive
 
diff --git a/e2e/receive/switchboard_test.go b/e2e/receive/switchboard_test.go
index 7d2f8c4ceff37b2be6a6abe09675d0e50a6822dc..9edc9526f82df58c37e5a69c07ff7ffd943d63e1 100644
--- a/e2e/receive/switchboard_test.go
+++ b/e2e/receive/switchboard_test.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package receive
 
diff --git a/e2e/rekey/compileProtobuf.sh b/e2e/rekey/compileProtobuf.sh
new file mode 100644
index 0000000000000000000000000000000000000000..cdead4cfb3925ddd4acc58fab7d8436f76e58206
--- /dev/null
+++ b/e2e/rekey/compileProtobuf.sh
@@ -0,0 +1,14 @@
+#!/bin/bash
+################################################################################
+## Copyright © 2022 xx foundation                                             ##
+##                                                                            ##
+## Use of this source code is governed by a license that can be found in the  ##
+## LICENSE file.                                                              ##
+################################################################################
+
+# This script will compile the Protobuf file to a Go file (pb.go).
+# This is meant to be called from the top level of the repo.
+
+cd ./e2e/rekey/ || return
+
+protoc --go_out=. --go_opt=paths=source_relative ./xchange.proto
diff --git a/e2e/rekey/confirm.go b/e2e/rekey/confirm.go
index 449aefddbbd2bd3723545ad03c1df5f9424757f9..4e399584a95bf26ff3db3909f920fae43e256b1a 100644
--- a/e2e/rekey/confirm.go
+++ b/e2e/rekey/confirm.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package rekey
 
diff --git a/e2e/rekey/confirm_test.go b/e2e/rekey/confirm_test.go
index 24de5fda04353b367d1d222d1517f48c09fb7cde..28623e1a97d58193b24ed4f840c96c48d35d181f 100644
--- a/e2e/rekey/confirm_test.go
+++ b/e2e/rekey/confirm_test.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package rekey
 
diff --git a/e2e/rekey/exchange.go b/e2e/rekey/exchange.go
index 30345ca1a28cf7b30ea8db9fd6587289e4092aec..f90baf0f0909b76ecb6bb64cca4526c7a00e4132 100644
--- a/e2e/rekey/exchange.go
+++ b/e2e/rekey/exchange.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package rekey
 
@@ -16,12 +16,10 @@ import (
 	"gitlab.com/elixxir/crypto/cyclic"
 	"gitlab.com/elixxir/crypto/e2e"
 	"gitlab.com/xx_network/primitives/id"
-	"time"
 )
 
 type E2eSender func(mt catalog.MessageType, recipient *id.ID, payload []byte,
-	cmixParams cmix.CMIXParams) (
-	[]id.Round, e2e.MessageID, time.Time, error)
+	cmixParams cmix.CMIXParams) (e2e.SendReport, error)
 
 func Start(switchboard *receive.Switchboard, ratchet *ratchet.Ratchet,
 	sender E2eSender, net cmix.Client, grp *cyclic.Group, params Params) (stoppable.Stoppable, error) {
diff --git a/e2e/rekey/exchange_test.go b/e2e/rekey/exchange_test.go
index 2967d81cbf2cea380ae1c0e64393fbe493fa1851..a6b2f7fa1e87070ba102a94bbc585fa29437fb95 100644
--- a/e2e/rekey/exchange_test.go
+++ b/e2e/rekey/exchange_test.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package rekey
 
diff --git a/e2e/rekey/generate.sh b/e2e/rekey/generate.sh
deleted file mode 100644
index cc5d530cece9c8a16123c820cc249f5db7216686..0000000000000000000000000000000000000000
--- a/e2e/rekey/generate.sh
+++ /dev/null
@@ -1,3 +0,0 @@
-#!/bin/bash
-
-protoc --go_out=. -I../ -I$PWD --go_opt=paths=source_relative xchange.proto
diff --git a/e2e/rekey/params.go b/e2e/rekey/params.go
index 274770c112329cb552a85df55c6abc6d273cf67c..988526e7a7f4bf18ad3e16ce29063ca22113c52b 100644
--- a/e2e/rekey/params.go
+++ b/e2e/rekey/params.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package rekey
 
 import (
diff --git a/e2e/rekey/rekey.go b/e2e/rekey/rekey.go
index 960df918f20e3aee3e87a77ac4959668fc5db87c..c66e3c241637ae4d3984fc69002f74445337d141 100644
--- a/e2e/rekey/rekey.go
+++ b/e2e/rekey/rekey.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package rekey
 
@@ -125,7 +125,8 @@ func negotiate(instance *commsNetwork.Instance, grp *cyclic.Group, sendE2E E2eSe
 	params := cmix.GetDefaultCMIXParams()
 	params.DebugTag = "kx.Request"
 
-	rounds, msgID, _, err := sendE2E(param.Trigger, sess.GetPartner(),
+	// fixme: should this use the key residue?
+	sendReport, err := sendE2E(param.Trigger, sess.GetPartner(),
 		payload, params)
 	// If the send fails, returns the error so it can be handled. The caller
 	// should ensure the calling session is in a state where the Rekey will
@@ -137,18 +138,18 @@ func negotiate(instance *commsNetwork.Instance, grp *cyclic.Group, sendE2E E2eSe
 	}
 
 	//create the runner which will handle the result of sending the messages
-	sendResults := make(chan ds.EventReturn, len(rounds))
+	sendResults := make(chan ds.EventReturn, len(sendReport.RoundList))
 
 	//Register the event for all rounds
 	roundEvents := instance.GetRoundEvents()
-	for _, r := range rounds {
+	for _, r := range sendReport.RoundList {
 		roundEvents.AddRoundEventChan(r, sendResults, sendTimeout,
 			states.COMPLETED, states.FAILED)
 	}
 
 	//Wait until the result tracking responds
 	success, numRoundFail, numTimeOut := cmix.TrackResults(sendResults,
-		len(rounds))
+		len(sendReport.RoundList))
 
 	// If a single partition of the Key Negotiation request does not
 	// transmit, the partner cannot read the result. Log the error and set
@@ -157,14 +158,14 @@ func negotiate(instance *commsNetwork.Instance, grp *cyclic.Group, sendE2E E2eSe
 		_ = sess.TrySetNegotiationStatus(session.Unconfirmed)
 		return errors.Errorf("[REKEY] Key Negotiation rekey for %s failed to "+
 			"transmit %v/%v paritions: %v round failures, %v timeouts, msgID: %s",
-			sess, numRoundFail+numTimeOut, len(rounds), numRoundFail,
-			numTimeOut, msgID)
+			sess, numRoundFail+numTimeOut, len(sendReport.RoundList), numRoundFail,
+			numTimeOut, sendReport.MessageId)
 	}
 
 	// otherwise, the transmission is a success and this should be denoted
 	// in the session and the log
 	jww.INFO.Printf("[REKEY] Key Negotiation rekey transmission for %s, msgID %s successful",
-		sess, msgID)
+		sess, sendReport.MessageId)
 	err = sess.TrySetNegotiationStatus(session.Sent)
 	if err != nil {
 		if sess.NegotiationStatus() == session.NewSessionTriggered {
diff --git a/e2e/rekey/rekey_test.go b/e2e/rekey/rekey_test.go
index ac5afe5fd8b9feb256e7b47c7dccc1efd85500be..58769e9acb197b39ca90e1202e2a503333f98909 100644
--- a/e2e/rekey/rekey_test.go
+++ b/e2e/rekey/rekey_test.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package rekey
 
diff --git a/e2e/rekey/trigger.go b/e2e/rekey/trigger.go
index 80d2cd2b62a8a1840e8605aa79bc7d4e501cbb2d..0567c3c341f6b9f35b1b8d239dc3b65658a2c2b1 100644
--- a/e2e/rekey/trigger.go
+++ b/e2e/rekey/trigger.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package rekey
 
@@ -127,7 +127,8 @@ func handleTrigger(ratchet *ratchet.Ratchet, sender E2eSender,
 	params := cmix.GetDefaultCMIXParams()
 	params.Critical = true
 	//ignore results, the passed sender interface makes it a critical message
-	_, _, _, _ = sender(param.Confirm, request.Sender, payload,
+	// fixme: should this ignore the error as well?
+	_, _ = sender(param.Confirm, request.Sender, payload,
 		params)
 
 	return nil
diff --git a/e2e/rekey/trigger_test.go b/e2e/rekey/trigger_test.go
index 8e9ab6658eb627babb1dd9acacd0150222f1a71c..0384d1b6a70c732bda30fd628cd16870142432cb 100644
--- a/e2e/rekey/trigger_test.go
+++ b/e2e/rekey/trigger_test.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package rekey
 
@@ -119,7 +119,8 @@ func TestHandleTrigger(t *testing.T) {
 	rekeyParams := GetDefaultParams()
 	stop := stoppable.NewSingle("stoppable")
 	rekeyParams.RoundTimeout = 0 * time.Second
-	err = handleTrigger(r, testSendE2E, &mockNetManager{}, grp, receiveMsg, rekeyParams, stop)
+	err = handleTrigger(r, testSendE2E, &mockNetManager{}, grp, receiveMsg,
+		rekeyParams, stop)
 	if err != nil {
 		t.Errorf("Handle trigger error: %v", err)
 	}
diff --git a/e2e/rekey/utils_test.go b/e2e/rekey/utils_test.go
index 3e1f77f1dcdc80a760498da5ea6b1905b90cec84..0b9fd388668ff77f9cbfed8bc7dc6dc6572d3eeb 100644
--- a/e2e/rekey/utils_test.go
+++ b/e2e/rekey/utils_test.go
@@ -1,13 +1,14 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package rekey
 
 import (
+	"gitlab.com/elixxir/crypto/e2e"
 	"math/rand"
 	"testing"
 	"time"
@@ -27,7 +28,6 @@ import (
 	network2 "gitlab.com/elixxir/comms/network"
 	ds "gitlab.com/elixxir/comms/network/dataStructures"
 	"gitlab.com/elixxir/crypto/cyclic"
-	"gitlab.com/elixxir/crypto/e2e"
 	"gitlab.com/elixxir/crypto/hash"
 	"gitlab.com/elixxir/primitives/format"
 	"gitlab.com/xx_network/comms/connect"
@@ -73,7 +73,8 @@ func genSidhKeys() (*sidh.PrivateKey, *sidh.PublicKey, *sidh.PrivateKey, *sidh.P
 }
 
 func testSendE2E(mt catalog.MessageType, recipient *id.ID,
-	payload []byte, cmixParams cmix.CMIXParams) ([]id.Round, e2e.MessageID, time.Time, error) {
+	payload []byte, cmixParams cmix.CMIXParams) (
+	e2e.SendReport, error) {
 	rounds := []id.Round{id.Round(0), id.Round(1), id.Round(2)}
 	alicePartner, err := r.GetPartner(aliceID)
 	if err != nil {
@@ -109,7 +110,9 @@ func testSendE2E(mt catalog.MessageType, recipient *id.ID,
 
 	bobSwitchboard.Speak(confirmMessage)
 
-	return rounds, e2e.MessageID{}, time.Time{}, nil
+	return e2e.SendReport{
+		RoundList: rounds,
+	}, nil
 }
 
 var pub = "-----BEGIN CERTIFICATE-----\nMIIGHTCCBAWgAwIBAgIUOcAn9cpH+hyRH8/UfqtbFDoSxYswDQYJKoZIhvcNAQEL\nBQAwgZIxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTESMBAGA1UEBwwJQ2xhcmVt\nb250MRAwDgYDVQQKDAdFbGl4eGlyMRQwEgYDVQQLDAtEZXZlbG9wbWVudDEZMBcG\nA1UEAwwQZ2F0ZXdheS5jbWl4LnJpcDEfMB0GCSqGSIb3DQEJARYQYWRtaW5AZWxp\neHhpci5pbzAeFw0xOTA4MTYwMDQ4MTNaFw0yMDA4MTUwMDQ4MTNaMIGSMQswCQYD\nVQQGEwJVUzELMAkGA1UECAwCQ0ExEjAQBgNVBAcMCUNsYXJlbW9udDEQMA4GA1UE\nCgwHRWxpeHhpcjEUMBIGA1UECwwLRGV2ZWxvcG1lbnQxGTAXBgNVBAMMEGdhdGV3\nYXkuY21peC5yaXAxHzAdBgkqhkiG9w0BCQEWEGFkbWluQGVsaXh4aXIuaW8wggIi\nMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC7Dkb6VXFn4cdpU0xh6ji0nTDQ\nUyT9DSNW9I3jVwBrWfqMc4ymJuonMZbuqK+cY2l+suS2eugevWZrtzujFPBRFp9O\n14Jl3fFLfvtjZvkrKbUMHDHFehascwzrp3tXNryiRMmCNQV55TfITVCv8CLE0t1i\nbiyOGM9ZWYB2OjXt59j76lPARYww5qwC46vS6+3Cn2Yt9zkcrGeskWEFa2VttHqF\n910TP+DZk2R5C7koAh6wZYK6NQ4S83YQurdHAT51LKGrbGehFKXq6/OAXCU1JLi3\nkW2PovTb6MZuvxEiRmVAONsOcXKu7zWCmFjuZZwfRt2RhnpcSgzfrarmsGM0LZh6\nJY3MGJ9YdPcVGSz+Vs2E4zWbNW+ZQoqlcGeMKgsIiQ670g0xSjYICqldpt79gaET\n9PZsoXKEmKUaj6pq1d4qXDk7s63HRQazwVLGBdJQK8qX41eCdR8VMKbrCaOkzD5z\ngnEu0jBBAwdMtcigkMIk1GRv91j7HmqwryOBHryLi6NWBY3tjb4So9AppDQB41SH\n3SwNenAbNO1CXeUqN0hHX6I1bE7OlbjqI7tXdrTllHAJTyVVjenPel2ApMXp+LVR\ndDbKtwBiuM6+n+z0I7YYerxN1gfvpYgcXm4uye8dfwotZj6H2J/uSALsU2v9UHBz\nprdrLSZk2YpozJb+CQIDAQABo2kwZzAdBgNVHQ4EFgQUDaTvG7SwgRQ3wcYx4l+W\nMcZjX7owHwYDVR0jBBgwFoAUDaTvG7SwgRQ3wcYx4l+WMcZjX7owDwYDVR0TAQH/\nBAUwAwEB/zAUBgNVHREEDTALgglmb28uY28udWswDQYJKoZIhvcNAQELBQADggIB\nADKz0ST0uS57oC4rT9zWhFqVZkEGh1x1XJ28bYtNUhozS8GmnttV9SnJpq0EBCm/\nr6Ub6+Wmf60b85vCN5WDYdoZqGJEBjGGsFzl4jkYEE1eeMfF17xlNUSdt1qLCE8h\nU0glr32uX4a6nsEkvw1vo1Liuyt+y0cOU/w4lgWwCqyweu3VuwjZqDoD+3DShVzX\n8f1p7nfnXKitrVJt9/uE+AtAk2kDnjBFbRxCfO49EX4Cc5rADUVXMXm0itquGBYp\nMbzSgFmsMp40jREfLYRRzijSZj8tw14c2U9z0svvK9vrLCrx9+CZQt7cONGHpr/C\n/GIrP/qvlg0DoLAtjea73WxjSCbdL3Nc0uNX/ymXVHdQ5husMCZbczc9LYdoT2VP\nD+GhkAuZV9g09COtRX4VP09zRdXiiBvweiq3K78ML7fISsY7kmc8KgVH22vcXvMX\nCgGwbrxi6QbQ80rWjGOzW5OxNFvjhvJ3vlbOT6r9cKZGIPY8IdN/zIyQxHiim0Jz\noavr9CPDdQefu9onizsmjsXFridjG/ctsJxcUEqK7R12zvaTxu/CVYZbYEUFjsCe\nq6ZAACiEJGvGeKbb/mSPvGs2P1kS70/cGp+P5kBCKqrm586FB7BcafHmGFrWhT3E\nLOUYkOV/gADT2hVDCrkPosg7Wb6ND9/mhCVVhf4hLGRh\n-----END CERTIFICATE-----\n"
@@ -233,13 +236,18 @@ func (m *mockNetManager) GetMaxMessageLength() int {
 
 func (m *mockNetManager) Send(recipient *id.ID, fingerprint format.Fingerprint,
 	service message.Service, payload, mac []byte, cmixParams cmix.CMIXParams) (
-	id.Round, ephemeral.Id, error) {
-	return id.Round(0), ephemeral.Id{}, nil
+	rounds.Round, ephemeral.Id, error) {
+	return rounds.Round{}, ephemeral.Id{}, nil
+}
+
+func (m *mockNetManager) SendWithAssembler(recipient *id.ID, assembler cmix.MessageAssembler,
+	cmixParams cmix.CMIXParams) (rounds.Round, ephemeral.Id, error) {
+	return rounds.Round{}, ephemeral.Id{}, nil
 }
 
 func (m *mockNetManager) SendMany(messages []cmix.TargetedCmixMessage, p cmix.CMIXParams) (
-	id.Round, []ephemeral.Id, error) {
-	return id.Round(0), nil, nil
+	rounds.Round, []ephemeral.Id, error) {
+	return rounds.Round{}, nil, nil
 }
 
 func (m *mockNetManager) AddIdentity(id *id.ID, validUntil time.Time, persistent bool) {}
@@ -294,8 +302,7 @@ func (m *mockNetManager) NumRegisteredNodes() int {
 func (m *mockNetManager) TriggerNodeRegistration(nid *id.ID) {}
 
 func (m *mockNetManager) GetRoundResults(timeout time.Duration, roundCallback cmix.RoundEventCallback,
-	roundList ...id.Round) error {
-	return nil
+	roundList ...id.Round) {
 }
 
 func (m *mockNetManager) LookupHistoricalRound(
diff --git a/e2e/rekey/xchange.pb.go b/e2e/rekey/xchange.pb.go
index a9b5f46ef0202e6b9e442b10f52c4298cf561489..48b98f7823388a708a2de226046bbf11bdb44ee2 100644
--- a/e2e/rekey/xchange.pb.go
+++ b/e2e/rekey/xchange.pb.go
@@ -1,15 +1,13 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
-
-// Call ./generate.sh to generate the protocol buffer code
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 // Code generated by protoc-gen-go. DO NOT EDIT.
 // versions:
-// 	protoc-gen-go v1.26.0
+// 	protoc-gen-go v1.27.1
 // 	protoc        v3.15.6
 // source: xchange.proto
 
@@ -147,7 +145,7 @@ var File_xchange_proto protoreflect.FileDescriptor
 
 var file_xchange_proto_rawDesc = []byte{
 	0x0a, 0x0d, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12,
-	0x05, 0x70, 0x61, 0x72, 0x73, 0x65, 0x22, 0x70, 0x0a, 0x0c, 0x52, 0x65, 0x6b, 0x65, 0x79, 0x54,
+	0x05, 0x72, 0x65, 0x6b, 0x65, 0x79, 0x22, 0x70, 0x0a, 0x0c, 0x52, 0x65, 0x6b, 0x65, 0x79, 0x54,
 	0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x12, 0x1c, 0x0a, 0x09, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63,
 	0x4b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x70, 0x75, 0x62, 0x6c, 0x69,
 	0x63, 0x4b, 0x65, 0x79, 0x12, 0x24, 0x0a, 0x0d, 0x73, 0x69, 0x64, 0x68, 0x50, 0x75, 0x62, 0x6c,
@@ -157,10 +155,10 @@ var file_xchange_proto_rawDesc = []byte{
 	0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x22, 0x2c, 0x0a, 0x0c, 0x52, 0x65, 0x6b, 0x65,
 	0x79, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x65, 0x73, 0x73,
 	0x69, 0x6f, 0x6e, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x73, 0x65, 0x73,
-	0x73, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x42, 0x27, 0x5a, 0x25, 0x67, 0x69, 0x74, 0x6c, 0x61, 0x62,
+	0x73, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x42, 0x25, 0x5a, 0x23, 0x67, 0x69, 0x74, 0x6c, 0x61, 0x62,
 	0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x65, 0x6c, 0x69, 0x78, 0x78, 0x69, 0x72, 0x2f, 0x63, 0x6c, 0x69,
-	0x65, 0x6e, 0x74, 0x2f, 0x6b, 0x65, 0x79, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x62,
-	0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+	0x65, 0x6e, 0x74, 0x2f, 0x65, 0x32, 0x65, 0x2f, 0x72, 0x65, 0x6b, 0x65, 0x79, 0x62, 0x06, 0x70,
+	0x72, 0x6f, 0x74, 0x6f, 0x33,
 }
 
 var (
@@ -177,8 +175,8 @@ func file_xchange_proto_rawDescGZIP() []byte {
 
 var file_xchange_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
 var file_xchange_proto_goTypes = []interface{}{
-	(*RekeyTrigger)(nil), // 0: parse.RekeyTrigger
-	(*RekeyConfirm)(nil), // 1: parse.RekeyConfirm
+	(*RekeyTrigger)(nil), // 0: rekey.RekeyTrigger
+	(*RekeyConfirm)(nil), // 1: rekey.RekeyConfirm
 }
 var file_xchange_proto_depIdxs = []int32{
 	0, // [0:0] is the sub-list for method output_type
diff --git a/e2e/rekey/xchange.proto b/e2e/rekey/xchange.proto
index 48fda885b39d7a4368e96286f0e4dc95787482db..efd3fe49f5c6d8cbb2677d7cc03a1949b123a1f1 100644
--- a/e2e/rekey/xchange.proto
+++ b/e2e/rekey/xchange.proto
@@ -1,17 +1,15 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
-
-// Call ./generate.sh to generate the protocol buffer code
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 syntax = "proto3";
 
-package parse;
-option go_package = "gitlab.com/elixxir/client/keyExchange";
+package rekey;
 
+option go_package = "gitlab.com/elixxir/client/e2e/rekey";
 
 message RekeyTrigger {
     // PublicKey used in the rekey
diff --git a/e2e/sendE2E.go b/e2e/sendE2E.go
index 284008a92d92988b56abb6f6e81fd49381be94e0..c05700842e7264a04358be6803e8ac4ed038afb9 100644
--- a/e2e/sendE2E.go
+++ b/e2e/sendE2E.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package e2e
 
 import (
@@ -19,11 +26,24 @@ import (
 	"gitlab.com/xx_network/primitives/netTime"
 )
 
+// SendE2E send a message containing the payload to the
+// recipient of the passed message type, per the given
+// parameters - encrypted with end-to-end encryption.
+// Default parameters can be retrieved through
+// GetDefaultParams()
+// If too long, it will chunk a message up into its messages
+// and send each as a separate cmix message. It will return
+// the list of all rounds sent on, a unique ID for the
+// message, and the timestamp sent on.
+// the recipient must already have an e2e relationship,
+// otherwise an error will be returned.
+// Will return an error if the network is not healthy or in
+// the event of a failed send
 func (m *manager) SendE2E(mt catalog.MessageType, recipient *id.ID,
-	payload []byte, params Params) ([]id.Round, e2e.MessageID, time.Time, error) {
+	payload []byte, params Params) (e2e.SendReport, error) {
 
 	if !m.net.IsHealthy() {
-		return nil, e2e.MessageID{}, time.Time{},
+		return e2e.SendReport{},
 			errors.New("cannot sendE2E when network is not healthy")
 	}
 
@@ -35,18 +55,18 @@ func (m *manager) SendE2E(mt catalog.MessageType, recipient *id.ID,
 		params.Critical = false
 	}
 
-	rounds, msgID, t, err := m.sendE2E(mt, recipient, payload, params)
+	sendReport, err := m.sendE2E(mt, recipient, payload, params)
 
 	if handleCritical {
-		m.crit.handle(mt, recipient, payload, rounds, err)
+		m.crit.handle(mt, recipient, payload, sendReport.RoundList, err)
 	}
-	return rounds, msgID, t, err
+	return sendReport, err
 
 }
 
 // sendE2eFn contains a prepared sendE2E operation and sends an E2E message when
 // called, returning the results of the send.
-type sendE2eFn func() ([]id.Round, e2e.MessageID, time.Time, error)
+type sendE2eFn func() (e2e.SendReport, error)
 
 // prepareSendE2E makes a prepared function that does the e2e send.
 // This is so that when doing deletePartner we can prepare the send before
@@ -63,41 +83,46 @@ func (m *manager) prepareSendE2E(mt catalog.MessageType, recipient *id.ID,
 	partitions, internalMsgId, err := m.partitioner.Partition(recipient,
 		mt, ts, payload)
 	if err != nil {
-		return nil, errors.WithMessage(err, "failed to send unsafe message")
+		return nil, errors.WithMessage(err,
+			"failed to send unsafe message")
 	}
 
-	jww.INFO.Printf("E2E sending %d messages to %s", len(partitions), recipient)
+	jww.INFO.Printf("E2E sending %d messages to %s",
+		len(partitions), recipient)
 
-	// When sending E2E messages, we first partition into cMix packets and then
-	// send each partition over cMix
+	// When sending E2E messages, we first partition into cMix
+	// packets and then send each partition over cMix
 	roundIds := make([]id.Round, len(partitions))
 	errCh := make(chan error, len(partitions))
 
-	// The Key manager for the partner (recipient) ensures single use of each
-	// key negotiated for the ratchet
+	// The Key manager for the partner (recipient) ensures single
+	// use of each key negotiated for the ratchet
 	partner, err := m.Ratchet.GetPartner(recipient)
 	if err != nil {
 		return nil, errors.WithMessagef(err,
-			"cannot send E2E message no relationship found with %s", recipient)
+			"cannot send E2E message no relationship found with %s",
+			recipient)
 	}
 
 	msgID := e2e.NewMessageID(
 		partner.SendRelationshipFingerprint(), internalMsgId)
 
 	wg := sync.WaitGroup{}
-
+	var keyResidue e2e.KeyResidue
 	for i, p := range partitions {
 		if mt != catalog.KeyExchangeTrigger {
 			// Check if any rekeys need to happen and trigger them
-			rekeySendFunc := func(mt catalog.MessageType, recipient *id.ID,
+			rekeySendFunc := func(mt catalog.MessageType,
+				recipient *id.ID,
 				payload []byte, cmixParams cmix.CMIXParams) (
-				[]id.Round, e2e.MessageID, time.Time, error) {
+				e2e.SendReport, error) {
 				par := params
 				par.CMIXParams = cmixParams
 				return m.SendE2E(mt, recipient, payload, par)
 			}
-			rekey.CheckKeyExchanges(m.net.GetInstance(), m.grp, rekeySendFunc,
-				m.events, partner, m.rekeyParams, 1*time.Minute)
+			rekey.CheckKeyExchanges(m.net.GetInstance(), m.grp,
+				rekeySendFunc, m.events, partner,
+				m.rekeyParams, 1*time.Minute)
 		}
 
 		var keyGetter func() (session.Cypher, error)
@@ -107,23 +132,29 @@ func (m *manager) prepareSendE2E(mt catalog.MessageType, recipient *id.ID,
 			keyGetter = partner.PopSendCypher
 		}
 
-		// FIXME: remove this wait, it is weird. Why is it here? we cant remember.
+		// FIXME: remove this wait, it is weird. Why is it
+		// here? we cant remember.
 		key, err := waitForKey(
-			keyGetter, params.KeyGetRetryCount, params.KeyGeRetryDelay,
+			keyGetter, params.KeyGetRetryCount,
+			params.KeyGeRetryDelay,
 			params.Stop, recipient, format.DigestContents(p), i)
 		if err != nil {
 			return nil, errors.WithMessagef(err,
 				"Failed to get key for end-to-end encryption")
 		}
 
-		// This does not encrypt for cMix but instead end-to-end encrypts the
-		// cMix message
-		contentsEnc, mac := key.Encrypt(p)
+		// This does not encrypt for cMix but instead
+		// end-to-end encrypts the cMix message
+		contentsEnc, mac, residue := key.Encrypt(p)
+		// Carry the first key residue to the top level
+		if i == 0 {
+			keyResidue = residue
+		}
 
-		jww.INFO.Printf(
-			"E2E sending %d/%d to %s with key fp: %s, msgID: %s (msgDigest %s)",
-			i+i, len(partitions), recipient, key.Fingerprint(), msgID,
-			format.DigestContents(p))
+		jww.INFO.Printf("E2E sending %d/%d to %s with key fp: %s, "+
+			"msgID: %s (msgDigest %s)",
+			i+i, len(partitions), recipient, key.Fingerprint(),
+			msgID, format.DigestContents(p))
 
 		var s message.Service
 		if i == len(partitions)-1 {
@@ -132,25 +163,29 @@ func (m *manager) prepareSendE2E(mt catalog.MessageType, recipient *id.ID,
 			s = partner.MakeService(params.ServiceTag)
 		}
 
-		// We send each partition in its own thread here; some may send in round
-		// X, others in X+1 or X+2, and so on
+		// We send each partition in its own thread here; some
+		// may send in round X, others in X+1 or X+2, and so
+		// on
 		localI := i
 		thisSendFunc := func() {
 			wg.Add(1)
 			go func(i int) {
-				var err error
-				roundIds[i], _, err = m.net.Send(recipient,
-					key.Fingerprint(), s, contentsEnc, mac, params.CMIXParams)
+				r, _, err := m.net.Send(recipient,
+					key.Fingerprint(), s, contentsEnc, mac,
+					params.CMIXParams)
 				if err != nil {
+					jww.DEBUG.Printf("[E2E] cMix error on "+
+						"Send: %+v", err)
 					errCh <- err
 				}
+				roundIds[i] = r.ID
 				wg.Done()
 			}(localI)
 		}
 		sendFuncs = append(sendFuncs, thisSendFunc)
 	}
 
-	sendE2E = func() ([]id.Round, e2e.MessageID, time.Time, error) {
+	sendE2E = func() (e2e.SendReport, error) {
 		for i := range sendFuncs {
 			sendFuncs[i]()
 		}
@@ -161,27 +196,33 @@ func (m *manager) prepareSendE2E(mt catalog.MessageType, recipient *id.ID,
 		if numFail > 0 {
 			jww.INFO.Printf("Failed to E2E send %d/%d to %s",
 				numFail, len(partitions), recipient)
-			return nil, e2e.MessageID{}, time.Time{}, errors.Errorf(
+			return e2e.SendReport{}, errors.Errorf(
 				"Failed to E2E send %v/%v sub payloads: %s",
 				numFail, len(partitions), errRtn)
 		} else {
 			jww.INFO.Printf("Successfully E2E sent %d/%d to %s",
-				len(partitions)-numFail, len(partitions), recipient)
+				len(partitions)-numFail, len(partitions),
+				recipient)
 		}
 
-		jww.INFO.Printf("Successful E2E Send of %d messages to %s with msgID %s",
-			len(partitions), recipient, msgID)
+		jww.INFO.Printf("Successful E2E Send of %d messages to %s "+
+			"with msgID %s", len(partitions), recipient, msgID)
 
-		return roundIds, msgID, ts, nil
+		return e2e.SendReport{
+			RoundList:  roundIds,
+			MessageId:  msgID,
+			SentTime:   ts,
+			KeyResidue: keyResidue,
+		}, nil
 	}
 	return sendE2E, nil
 }
 
 func (m *manager) sendE2E(mt catalog.MessageType, recipient *id.ID,
-	payload []byte, params Params) ([]id.Round, e2e.MessageID, time.Time, error) {
+	payload []byte, params Params) (e2e.SendReport, error) {
 	sendFunc, err := m.prepareSendE2E(mt, recipient, payload, params)
 	if err != nil {
-		return nil, e2e.MessageID{}, time.Time{}, err
+		return e2e.SendReport{}, err
 	}
 	return sendFunc()
 }
diff --git a/e2e/sendE2E_test.go b/e2e/sendE2E_test.go
index d316b90c79a388ac32c405542e49d882089138d1..58afc0e9c3062ee0b768deff58004cb6f45bfdbf 100644
--- a/e2e/sendE2E_test.go
+++ b/e2e/sendE2E_test.go
@@ -1,8 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package e2e
@@ -22,6 +22,7 @@ import (
 	"gitlab.com/elixxir/client/storage/versioned"
 	"gitlab.com/elixxir/crypto/cyclic"
 	dh "gitlab.com/elixxir/crypto/diffieHellman"
+	"gitlab.com/elixxir/crypto/e2e"
 	"gitlab.com/elixxir/crypto/fastRNG"
 	"gitlab.com/elixxir/ekv"
 	"gitlab.com/elixxir/primitives/format"
@@ -106,7 +107,7 @@ func Test_manager_SendE2E_Smoke(t *testing.T) {
 
 	payload := []byte("My Payload")
 	p := GetDefaultParams()
-	_, _, _, err = m1.SendE2E(catalog.NoType, partnerID, payload, p)
+	_, err = m1.SendE2E(catalog.NoType, partnerID, payload, p)
 	if err != nil {
 		t.Errorf("SendE2E failed: %+v", err)
 	}
@@ -221,11 +222,15 @@ type mockWaitForKeyCypher struct {
 	cypherNum int
 }
 
-func (m *mockWaitForKeyCypher) GetSession() *session.Session           { return nil }
-func (m *mockWaitForKeyCypher) Fingerprint() format.Fingerprint        { return format.Fingerprint{} }
-func (m *mockWaitForKeyCypher) Encrypt([]byte) ([]byte, []byte)        { return nil, nil }
-func (m *mockWaitForKeyCypher) Decrypt(format.Message) ([]byte, error) { return nil, nil }
-func (m *mockWaitForKeyCypher) Use()                                   {}
+func (m *mockWaitForKeyCypher) GetSession() *session.Session    { return nil }
+func (m *mockWaitForKeyCypher) Fingerprint() format.Fingerprint { return format.Fingerprint{} }
+func (m *mockWaitForKeyCypher) Encrypt([]byte) ([]byte, []byte, e2e.KeyResidue) {
+	return nil, nil, e2e.KeyResidue{}
+}
+func (m *mockWaitForKeyCypher) Decrypt(format.Message) ([]byte, e2e.KeyResidue, error) {
+	return nil, e2e.KeyResidue{}, nil
+}
+func (m *mockWaitForKeyCypher) Use() {}
 
 // Tests that getSendErrors returns all the errors on the channel.
 func Test_getSendErrors(t *testing.T) {
diff --git a/e2e/sendUnsafe.go b/e2e/sendUnsafe.go
index 4451f16c4f12062dee8ee883ccc10de83f225e69..b59bd3243bfb6a9208c302761580cf6f90417983 100644
--- a/e2e/sendUnsafe.go
+++ b/e2e/sendUnsafe.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package e2e
 
 import (
@@ -65,13 +72,13 @@ func (m *manager) sendUnsafe(mt catalog.MessageType, recipient *id.ID,
 			jww.TRACE.Printf("sendUnsafe contents: %v, fp: %v, mac: %v",
 				payload, fp, unencryptedMAC)
 
-			var err error
-			roundIds[i], _, err = m.net.Send(recipient, fp,
+			r, _, err := m.net.Send(recipient, fp,
 				srvc, payload, unencryptedMAC,
 				params.CMIXParams)
 			if err != nil {
 				errCh <- err
 			}
+			roundIds[i] = r.ID
 			wg.Done()
 		}(i, p)
 	}
diff --git a/e2e/sendUnsafe_test.go b/e2e/sendUnsafe_test.go
index d30e6e15f9c2f6e8673e2f790c83199045d0c9c2..0df0532e61a3035c8e6ea6a4e2bc0355beeb911f 100644
--- a/e2e/sendUnsafe_test.go
+++ b/e2e/sendUnsafe_test.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package e2e
 
diff --git a/e2e/unsafeProcessor.go b/e2e/unsafeProcessor.go
index 3cd173d525244ea2bdb15cd1c28fe4af1847ce58..5f1c7fb3eb7094e49d00b49b426f093e25745a60 100644
--- a/e2e/unsafeProcessor.go
+++ b/e2e/unsafeProcessor.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package e2e
 
 import (
@@ -33,8 +40,9 @@ func (up *UnsafeProcessor) Process(ecrMsg format.Message,
 	}
 
 	//Parse
-	message, done := up.m.partitioner.HandlePartition(sender,
-		ecrMsg.GetContents(), nil)
+	// todo: handle residue here
+	message, _, done := up.m.partitioner.HandlePartition(sender,
+		ecrMsg.GetContents(), nil, e2e.KeyResidue{})
 
 	if done {
 		message.RecipientID = receptionID.Source
diff --git a/e2e/util.go b/e2e/util.go
index dad7da4702ad53ac2ee1a4c4fed55dfd5814b9e7..f8fc28c2a3e4b2efbaf8a5ed7d72e141883bd802 100644
--- a/e2e/util.go
+++ b/e2e/util.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package e2e
 
 import (
diff --git a/e2e/utils_test.go b/e2e/utils_test.go
index 72bcfb3402d76c2d22b8351f1283a367ba771fc9..6d8835b8c51edaf47ca2821521e9e55de95f5db3 100644
--- a/e2e/utils_test.go
+++ b/e2e/utils_test.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package e2e
 
 import (
@@ -174,7 +181,7 @@ func (m *mockCmix) GetMaxMessageLength() int {
 }
 
 func (m *mockCmix) Send(_ *id.ID, fp format.Fingerprint, srv message.Service,
-	payload, mac []byte, _ cmix.CMIXParams) (id.Round, ephemeral.Id, error) {
+	payload, mac []byte, _ cmix.CMIXParams) (rounds.Round, ephemeral.Id, error) {
 	m.handler.Lock()
 	defer m.handler.Unlock()
 
@@ -186,21 +193,26 @@ func (m *mockCmix) Send(_ *id.ID, fp format.Fingerprint, srv message.Service,
 	if m.handler.processorMap[fp] != nil {
 		m.handler.processorMap[fp].Process(
 			msg, receptionID.EphemeralIdentity{}, rounds.Round{})
-		return 0, ephemeral.Id{}, nil
+		return rounds.Round{}, ephemeral.Id{}, nil
 	} else if m.handler.serviceMap[srv.Tag] != nil {
 		m.handler.serviceMap[srv.Tag].Process(
 			msg, receptionID.EphemeralIdentity{}, rounds.Round{})
-		return 0, ephemeral.Id{}, nil
+		return rounds.Round{}, ephemeral.Id{}, nil
 	}
 
 	m.t.Errorf("No processor found for fingerprint %s", fp)
-	return 0, ephemeral.Id{},
+	return rounds.Round{}, ephemeral.Id{},
 		errors.Errorf("No processor found for fingerprint %s", fp)
 
 }
 
-func (m *mockCmix) SendMany([]cmix.TargetedCmixMessage, cmix.CMIXParams) (id.Round, []ephemeral.Id, error) {
-	return 0, nil, nil
+func (m *mockCmix) SendWithAssembler(recipient *id.ID, assembler cmix.MessageAssembler,
+	cmixParams cmix.CMIXParams) (rounds.Round, ephemeral.Id, error) {
+	panic("implement me")
+}
+
+func (m *mockCmix) SendMany([]cmix.TargetedCmixMessage, cmix.CMIXParams) (rounds.Round, []ephemeral.Id, error) {
+	return rounds.Round{}, nil, nil
 }
 func (m *mockCmix) AddIdentity(*id.ID, time.Time, bool)            {}
 func (m *mockCmix) RemoveIdentity(*id.ID)                          {}
@@ -238,8 +250,7 @@ func (m *mockCmix) RemoveHealthCallback(uint64)                              {}
 func (m *mockCmix) HasNode(*id.ID) bool                                      { return true }
 func (m *mockCmix) NumRegisteredNodes() int                                  { return 0 }
 func (m *mockCmix) TriggerNodeRegistration(*id.ID)                           {}
-func (m *mockCmix) GetRoundResults(time.Duration, cmix.RoundEventCallback, ...id.Round) error {
-	return nil
+func (m *mockCmix) GetRoundResults(time.Duration, cmix.RoundEventCallback, ...id.Round) {
 }
 func (m *mockCmix) LookupHistoricalRound(id.Round, rounds.RoundResultCallback) error { return nil }
 func (m *mockCmix) SendToAny(func(host *connect.Host) (interface{}, error), *stoppable.Single) (interface{}, error) {
diff --git a/event/event.go b/event/event.go
index 1b017009e991c089bd9b7be930759bd2a1d3ffec..441fa394413d66d87259a744cf51ec7a595451d2 100644
--- a/event/event.go
+++ b/event/event.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package event
 
diff --git a/event/event_test.go b/event/event_test.go
index d657206bac2cbf2ed761ab454e6728484931a6f6..5ee6080ce8aff0ff2cabb0a11cc26c715fa9fa81 100644
--- a/event/event_test.go
+++ b/event/event_test.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package event
 
diff --git a/event/interface.go b/event/interface.go
index 867e4dd9c11760474240c27a3661b910b8fe061d..2ef24fd6d607508104c34f8b7cef7d34aae27950 100644
--- a/event/interface.go
+++ b/event/interface.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package event
 
diff --git a/fileTransfer/batchBuilder.go b/fileTransfer/batchBuilder.go
index 24749e77ad9c16deff40c2e489fd4a7f3f34ce08..6b529d5ba187394b85e207fb53024a733bd9ea12 100644
--- a/fileTransfer/batchBuilder.go
+++ b/fileTransfer/batchBuilder.go
@@ -1,8 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package fileTransfer
diff --git a/fileTransfer/callbackTracker/callbackTracker.go b/fileTransfer/callbackTracker/callbackTracker.go
index 441ee157ea0cd9296bd5424f2d026ee6df217489..40728d9b6437f88636a6621045862df969587a8d 100644
--- a/fileTransfer/callbackTracker/callbackTracker.go
+++ b/fileTransfer/callbackTracker/callbackTracker.go
@@ -1,8 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package callbackTracker
diff --git a/fileTransfer/callbackTracker/callbackTracker_test.go b/fileTransfer/callbackTracker/callbackTracker_test.go
index 7ffbe6636f3bc8abd56db36befbc699bfba22181..ad6882cc3833d42fe7133212945bab5b13a0ebcd 100644
--- a/fileTransfer/callbackTracker/callbackTracker_test.go
+++ b/fileTransfer/callbackTracker/callbackTracker_test.go
@@ -1,8 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package callbackTracker
diff --git a/fileTransfer/callbackTracker/manager.go b/fileTransfer/callbackTracker/manager.go
index e6c4cf437ad0d625454667950d2a136baa8f20d2..4f03b0e3e26d25ce0cf4c9adde5766b272244907 100644
--- a/fileTransfer/callbackTracker/manager.go
+++ b/fileTransfer/callbackTracker/manager.go
@@ -1,8 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package callbackTracker
diff --git a/fileTransfer/callbackTracker/manager_test.go b/fileTransfer/callbackTracker/manager_test.go
index 4226807f18a728345fc4907758bd27ae21b6dcc1..920fb2f9eb165e4731d91b243d91ad56b811e6c1 100644
--- a/fileTransfer/callbackTracker/manager_test.go
+++ b/fileTransfer/callbackTracker/manager_test.go
@@ -1,8 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package callbackTracker
diff --git a/fileTransfer/compileProtobuf.sh b/fileTransfer/compileProtobuf.sh
new file mode 100644
index 0000000000000000000000000000000000000000..1aea86bde01d7493ccec94c6e2138236eff834ed
--- /dev/null
+++ b/fileTransfer/compileProtobuf.sh
@@ -0,0 +1,14 @@
+#!/bin/bash
+################################################################################
+## Copyright © 2022 xx foundation                                             ##
+##                                                                            ##
+## Use of this source code is governed by a license that can be found in the  ##
+## LICENSE file.                                                              ##
+################################################################################
+
+# This script will compile the Protobuf file to a Go file (pb.go).
+# This is meant to be called from the top level of the repo.
+
+cd ./fileTransfer/ || return
+
+protoc --go_out=. --go_opt=paths=source_relative ./ftMessages.proto
diff --git a/fileTransfer/connect/listener.go b/fileTransfer/connect/listener.go
index 6eadbe4bc2222476d945e5aa23d4124a51b0f4db..12b64eb0f5f125cefaaa9b5dbda9ff52018e66ec 100644
--- a/fileTransfer/connect/listener.go
+++ b/fileTransfer/connect/listener.go
@@ -1,8 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package connect
diff --git a/fileTransfer/connect/params.go b/fileTransfer/connect/params.go
index bd36ef4f6addca4c0f7f6de98f9e7224bb725187..5382603ffc0c486b6b6e4951ee6d6fdb43781c24 100644
--- a/fileTransfer/connect/params.go
+++ b/fileTransfer/connect/params.go
@@ -1,8 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package connect
diff --git a/fileTransfer/connect/send.go b/fileTransfer/connect/send.go
index 2b00c8ba71cc8817a2764025ae34f8e4bdcc3438..dadd7b4d23f64035a17f2efc2db47a9146d74c51 100644
--- a/fileTransfer/connect/send.go
+++ b/fileTransfer/connect/send.go
@@ -1,8 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package connect
@@ -45,7 +45,7 @@ func sendNewFileTransferMessage(
 	params.LastServiceTag = catalog.Silent
 	params.DebugTag = initialMessageDebugTag
 
-	_, _, _, err := connectionHandler.SendE2E(
+	_, err := connectionHandler.SendE2E(
 		catalog.NewFileTransfer, transferInfo, params)
 	if err != nil {
 		return errors.Errorf(errNewFtSendE2e, err)
@@ -65,7 +65,7 @@ func sendEndFileTransferMessage(cmix ft.Cmix, connectionHandler connection) {
 				params.LastServiceTag = catalog.EndFT
 				params.DebugTag = lastMessageDebugTag
 
-				_, _, _, err := connectionHandler.SendE2E(
+				_, err := connectionHandler.SendE2E(
 					catalog.EndFileTransfer, nil, params)
 				if err != nil {
 					jww.ERROR.Printf(errEndFtSendE2e, err)
diff --git a/fileTransfer/connect/utils_test.go b/fileTransfer/connect/utils_test.go
index 7d0fb6aeba668c2fcccf89cd881746007a84a101..83d75d020beccafe57c72331b0595a05253c0470 100644
--- a/fileTransfer/connect/utils_test.go
+++ b/fileTransfer/connect/utils_test.go
@@ -1,8 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package connect
@@ -26,7 +26,7 @@ import (
 	"gitlab.com/elixxir/client/xxdk"
 	"gitlab.com/elixxir/comms/network"
 	"gitlab.com/elixxir/crypto/cyclic"
-	e2eCrypto "gitlab.com/elixxir/crypto/e2e"
+	cryptoE2e "gitlab.com/elixxir/crypto/e2e"
 	"gitlab.com/elixxir/crypto/fastRNG"
 	"gitlab.com/elixxir/ekv"
 	"gitlab.com/elixxir/primitives/format"
@@ -38,7 +38,6 @@ import (
 	"gitlab.com/xx_network/primitives/id"
 	"gitlab.com/xx_network/primitives/id/ephemeral"
 	"gitlab.com/xx_network/primitives/ndf"
-	"gitlab.com/xx_network/primitives/netTime"
 	"sync"
 	"testing"
 	"time"
@@ -116,12 +115,17 @@ func (m *mockCmix) GetMaxMessageLength() int {
 }
 
 func (m *mockCmix) Send(*id.ID, format.Fingerprint, message.Service, []byte,
-	[]byte, cmix.CMIXParams) (id.Round, ephemeral.Id, error) {
+	[]byte, cmix.CMIXParams) (rounds.Round, ephemeral.Id, error) {
+	panic("implement me")
+}
+
+func (m *mockCmix) SendWithAssembler(recipient *id.ID, assembler cmix.MessageAssembler,
+	cmixParams cmix.CMIXParams) (rounds.Round, ephemeral.Id, error) {
 	panic("implement me")
 }
 
 func (m *mockCmix) SendMany(messages []cmix.TargetedCmixMessage,
-	_ cmix.CMIXParams) (id.Round, []ephemeral.Id, error) {
+	_ cmix.CMIXParams) (rounds.Round, []ephemeral.Id, error) {
 	m.handler.Lock()
 	for _, targetedMsg := range messages {
 		msg := format.NewMessage(m.numPrimeBytes)
@@ -133,7 +137,7 @@ func (m *mockCmix) SendMany(messages []cmix.TargetedCmixMessage,
 			rounds.Round{ID: 42})
 	}
 	m.handler.Unlock()
-	return 42, []ephemeral.Id{}, nil
+	return rounds.Round{ID: 42}, []ephemeral.Id{}, nil
 }
 
 func (m *mockCmix) AddIdentity(*id.ID, time.Time, bool)            { panic("implement me") }
@@ -185,9 +189,8 @@ func (m *mockCmix) NumRegisteredNodes() int        { panic("implement me") }
 func (m *mockCmix) TriggerNodeRegistration(*id.ID) { panic("implement me") }
 
 func (m *mockCmix) GetRoundResults(_ time.Duration,
-	roundCallback cmix.RoundEventCallback, _ ...id.Round) error {
+	roundCallback cmix.RoundEventCallback, _ ...id.Round) {
 	go roundCallback(true, false, map[id.Round]cmix.RoundResult{42: {}})
-	return nil
 }
 
 func (m *mockCmix) LookupHistoricalRound(id.Round, rounds.RoundResultCallback) error {
@@ -268,7 +271,7 @@ func (m *mockConnection) GetPartner() partner.Manager {
 
 // SendE2E adds the message to the e2e handler map.
 func (m *mockConnection) SendE2E(mt catalog.MessageType, payload []byte,
-	_ e2e.Params) ([]id.Round, e2eCrypto.MessageID, time.Time, error) {
+	_ e2e.Params) (cryptoE2e.SendReport, error) {
 	m.handler.Lock()
 	defer m.handler.Unlock()
 
@@ -278,7 +281,7 @@ func (m *mockConnection) SendE2E(mt catalog.MessageType, payload []byte,
 		Sender:      m.myID,
 	})
 
-	return []id.Round{42}, e2eCrypto.MessageID{}, netTime.Now(), nil
+	return cryptoE2e.SendReport{RoundList: []id.Round{42}}, nil
 }
 
 func (m *mockConnection) RegisterListener(mt catalog.MessageType,
diff --git a/fileTransfer/connect/wrapper.go b/fileTransfer/connect/wrapper.go
index 60a3f6641da53aad60d53a29feb533180738556b..135985d0bdcb4613e4f5db7a183e32b2637c4519 100644
--- a/fileTransfer/connect/wrapper.go
+++ b/fileTransfer/connect/wrapper.go
@@ -1,8 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package connect
@@ -13,9 +13,8 @@ import (
 	"gitlab.com/elixxir/client/e2e/ratchet/partner"
 	"gitlab.com/elixxir/client/e2e/receive"
 	ft "gitlab.com/elixxir/client/fileTransfer"
-	e2eCrypto "gitlab.com/elixxir/crypto/e2e"
+	cryptoE2e "gitlab.com/elixxir/crypto/e2e"
 	ftCrypto "gitlab.com/elixxir/crypto/fileTransfer"
-	"gitlab.com/xx_network/primitives/id"
 	"time"
 )
 
@@ -41,7 +40,7 @@ type Wrapper struct {
 type connection interface {
 	GetPartner() partner.Manager
 	SendE2E(mt catalog.MessageType, payload []byte, params e2e.Params) (
-		[]id.Round, e2eCrypto.MessageID, time.Time, error)
+		cryptoE2e.SendReport, error)
 	RegisterListener(messageType catalog.MessageType,
 		newListener receive.Listener) (receive.ListenerID, error)
 }
diff --git a/fileTransfer/connect/wrapper_test.go b/fileTransfer/connect/wrapper_test.go
index a9b7552044d439c31c25a15e1cfb01be13f886bf..a8f38730cb7885d81713e6c9713bfd348f144075 100644
--- a/fileTransfer/connect/wrapper_test.go
+++ b/fileTransfer/connect/wrapper_test.go
@@ -1,8 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package connect
diff --git a/fileTransfer/delayedTimer.go b/fileTransfer/delayedTimer.go
index e07af67d67bf92fcb8807ca0cee48bcdd631beb1..085852e609f79130f5f905c813fa90834bca1eaf 100644
--- a/fileTransfer/delayedTimer.go
+++ b/fileTransfer/delayedTimer.go
@@ -1,8 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package fileTransfer
diff --git a/fileTransfer/e2e/listener.go b/fileTransfer/e2e/listener.go
index 4a07ed9d0682bc9e3af37d67e9e4dcc8902971dc..f2adcf2e2ecc5091a7b4eb1882ad94b90f43435a 100644
--- a/fileTransfer/e2e/listener.go
+++ b/fileTransfer/e2e/listener.go
@@ -1,8 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package e2e
diff --git a/fileTransfer/e2e/params.go b/fileTransfer/e2e/params.go
index 819e963f5fd9efc3d058b5a953e87c7aa8874f1f..07377414d0d8e084dc39a1a05fead9b40cf987d6 100644
--- a/fileTransfer/e2e/params.go
+++ b/fileTransfer/e2e/params.go
@@ -1,8 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package e2e
diff --git a/fileTransfer/e2e/send.go b/fileTransfer/e2e/send.go
index a073d0afe841a04026081b9033e0e1cc5c164062..2aa2b5a9bf84b528071f0540b8d076c6db26afd0 100644
--- a/fileTransfer/e2e/send.go
+++ b/fileTransfer/e2e/send.go
@@ -1,8 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package e2e
@@ -46,7 +46,7 @@ func sendNewFileTransferMessage(
 	params.LastServiceTag = catalog.Silent
 	params.DebugTag = initialMessageDebugTag
 
-	_, _, _, err := e2eHandler.SendE2E(
+	_, err := e2eHandler.SendE2E(
 		catalog.NewFileTransfer, recipient, transferInfo, params)
 	if err != nil {
 		return errors.Errorf(errNewFtSendE2e, err)
@@ -66,7 +66,7 @@ func sendEndFileTransferMessage(recipient *id.ID, cmix ft.Cmix, e2eHandler e2eHa
 				params.LastServiceTag = catalog.EndFT
 				params.DebugTag = lastMessageDebugTag
 
-				_, _, _, err := e2eHandler.SendE2E(
+				_, err := e2eHandler.SendE2E(
 					catalog.EndFileTransfer, recipient, nil, params)
 				if err != nil {
 					jww.ERROR.Printf(errEndFtSendE2e, err)
diff --git a/fileTransfer/e2e/utils_test.go b/fileTransfer/e2e/utils_test.go
index 164d155740c789916f1ff5a96b3bd3c89079c61f..a9e17b912810dbf24bf640d518bf2c434e95181b 100644
--- a/fileTransfer/e2e/utils_test.go
+++ b/fileTransfer/e2e/utils_test.go
@@ -1,8 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package e2e
@@ -28,7 +28,7 @@ import (
 	"gitlab.com/elixxir/client/xxdk"
 	"gitlab.com/elixxir/comms/network"
 	"gitlab.com/elixxir/crypto/cyclic"
-	e "gitlab.com/elixxir/crypto/e2e"
+	cryptoE2e "gitlab.com/elixxir/crypto/e2e"
 	"gitlab.com/elixxir/crypto/fastRNG"
 	"gitlab.com/elixxir/ekv"
 	"gitlab.com/elixxir/primitives/format"
@@ -40,7 +40,6 @@ import (
 	"gitlab.com/xx_network/primitives/id"
 	"gitlab.com/xx_network/primitives/id/ephemeral"
 	"gitlab.com/xx_network/primitives/ndf"
-	"gitlab.com/xx_network/primitives/netTime"
 	"sync"
 	"time"
 )
@@ -118,12 +117,17 @@ func (m *mockCmix) GetMaxMessageLength() int {
 }
 
 func (m *mockCmix) Send(*id.ID, format.Fingerprint, message.Service, []byte,
-	[]byte, cmix.CMIXParams) (id.Round, ephemeral.Id, error) {
+	[]byte, cmix.CMIXParams) (rounds.Round, ephemeral.Id, error) {
+	panic("implement me")
+}
+
+func (m *mockCmix) SendWithAssembler(recipient *id.ID, assembler cmix.MessageAssembler,
+	cmixParams cmix.CMIXParams) (rounds.Round, ephemeral.Id, error) {
 	panic("implement me")
 }
 
 func (m *mockCmix) SendMany(messages []cmix.TargetedCmixMessage,
-	_ cmix.CMIXParams) (id.Round, []ephemeral.Id, error) {
+	_ cmix.CMIXParams) (rounds.Round, []ephemeral.Id, error) {
 	m.handler.Lock()
 	for _, targetedMsg := range messages {
 		msg := format.NewMessage(m.numPrimeBytes)
@@ -135,7 +139,7 @@ func (m *mockCmix) SendMany(messages []cmix.TargetedCmixMessage,
 			rounds.Round{ID: 42})
 	}
 	m.handler.Unlock()
-	return 42, []ephemeral.Id{}, nil
+	return rounds.Round{ID: 42}, []ephemeral.Id{}, nil
 }
 
 func (m *mockCmix) AddIdentity(*id.ID, time.Time, bool)            { panic("implement me") }
@@ -187,9 +191,8 @@ func (m *mockCmix) NumRegisteredNodes() int        { panic("implement me") }
 func (m *mockCmix) TriggerNodeRegistration(*id.ID) { panic("implement me") }
 
 func (m *mockCmix) GetRoundResults(_ time.Duration,
-	roundCallback cmix.RoundEventCallback, _ ...id.Round) error {
+	roundCallback cmix.RoundEventCallback, _ ...id.Round) {
 	go roundCallback(true, false, map[id.Round]cmix.RoundResult{42: {}})
-	return nil
 }
 
 func (m *mockCmix) LookupHistoricalRound(id.Round, rounds.RoundResultCallback) error {
@@ -259,7 +262,7 @@ func (m *mockE2e) StartProcesses() (stoppable.Stoppable, error) { panic("impleme
 
 // SendE2E adds the message to the e2e handler map.
 func (m *mockE2e) SendE2E(mt catalog.MessageType, recipient *id.ID,
-	payload []byte, _ e2e.Params) ([]id.Round, e.MessageID, time.Time, error) {
+	payload []byte, _ e2e.Params) (cryptoE2e.SendReport, error) {
 
 	m.handler.listeners[mt].Hear(receive.Message{
 		MessageType: mt,
@@ -268,7 +271,7 @@ func (m *mockE2e) SendE2E(mt catalog.MessageType, recipient *id.ID,
 		RecipientID: recipient,
 	})
 
-	return []id.Round{42}, e.MessageID{}, netTime.Now(), nil
+	return cryptoE2e.SendReport{RoundList: []id.Round{42}}, nil
 }
 
 func (m *mockE2e) RegisterListener(_ *id.ID, mt catalog.MessageType,
diff --git a/fileTransfer/e2e/wrapper.go b/fileTransfer/e2e/wrapper.go
index e27c281c9dfc490d271b3d225b73643b9e75cfa2..ac575583b6ecb817dfdccad3aed61abc6db3fe5b 100644
--- a/fileTransfer/e2e/wrapper.go
+++ b/fileTransfer/e2e/wrapper.go
@@ -1,8 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package e2e
@@ -12,7 +12,7 @@ import (
 	"gitlab.com/elixxir/client/e2e"
 	"gitlab.com/elixxir/client/e2e/receive"
 	ft "gitlab.com/elixxir/client/fileTransfer"
-	e2eCrypto "gitlab.com/elixxir/crypto/e2e"
+	cryptoE2e "gitlab.com/elixxir/crypto/e2e"
 	ftCrypto "gitlab.com/elixxir/crypto/fileTransfer"
 	"gitlab.com/xx_network/primitives/id"
 	"time"
@@ -39,7 +39,7 @@ type Wrapper struct {
 // for easier testing.
 type e2eHandler interface {
 	SendE2E(mt catalog.MessageType, recipient *id.ID, payload []byte,
-		params e2e.Params) ([]id.Round, e2eCrypto.MessageID, time.Time, error)
+		params e2e.Params) (cryptoE2e.SendReport, error)
 	RegisterListener(senderID *id.ID, messageType catalog.MessageType,
 		newListener receive.Listener) receive.ListenerID
 }
diff --git a/fileTransfer/e2e/wrapper_test.go b/fileTransfer/e2e/wrapper_test.go
index 9ea7b46b5b586c95a1bcb0b92bf5e7412c229b02..c1924066a91828feafc071683b4ca21961158036 100644
--- a/fileTransfer/e2e/wrapper_test.go
+++ b/fileTransfer/e2e/wrapper_test.go
@@ -1,8 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package e2e
diff --git a/fileTransfer/ftMessages.pb.go b/fileTransfer/ftMessages.pb.go
index 7990ffe025c93eb8a97dd303bcd2e85bbeec2b24..3bde058fbcd1d3bab95d9ee4545f7e0616928a4f 100644
--- a/fileTransfer/ftMessages.pb.go
+++ b/fileTransfer/ftMessages.pb.go
@@ -1,149 +1,222 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 // Code generated by protoc-gen-go. DO NOT EDIT.
-// source: fileTransfer/ftMessages.proto
+// versions:
+// 	protoc-gen-go v1.27.1
+// 	protoc        v3.15.6
+// source: ftMessages.proto
 
 package fileTransfer
 
 import (
-	fmt "fmt"
-	proto "github.com/golang/protobuf/proto"
-	math "math"
+	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+	reflect "reflect"
+	sync "sync"
 )
 
-// Reference imports to suppress errors if they are not otherwise used.
-var _ = proto.Marshal
-var _ = fmt.Errorf
-var _ = math.Inf
-
-// This is a compile-time assertion to ensure that this generated file
-// is compatible with the proto package it is being compiled against.
-// A compilation error at this line likely means your copy of the
-// proto package needs to be updated.
-const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
+const (
+	// Verify that this generated code is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+	// Verify that runtime/protoimpl is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
 
 // NewFileTransfer is transmitted first on the initialization of a file transfer
 // to inform the receiver about the incoming file.
 type NewFileTransfer struct {
-	FileName             string   `protobuf:"bytes,1,opt,name=fileName,proto3" json:"fileName,omitempty"`
-	FileType             string   `protobuf:"bytes,2,opt,name=fileType,proto3" json:"fileType,omitempty"`
-	TransferKey          []byte   `protobuf:"bytes,3,opt,name=transferKey,proto3" json:"transferKey,omitempty"`
-	TransferMac          []byte   `protobuf:"bytes,4,opt,name=transferMac,proto3" json:"transferMac,omitempty"`
-	NumParts             uint32   `protobuf:"varint,5,opt,name=numParts,proto3" json:"numParts,omitempty"`
-	Size                 uint32   `protobuf:"varint,6,opt,name=size,proto3" json:"size,omitempty"`
-	Retry                float32  `protobuf:"fixed32,7,opt,name=retry,proto3" json:"retry,omitempty"`
-	Preview              []byte   `protobuf:"bytes,8,opt,name=preview,proto3" json:"preview,omitempty"`
-	XXX_NoUnkeyedLiteral struct{} `json:"-"`
-	XXX_unrecognized     []byte   `json:"-"`
-	XXX_sizecache        int32    `json:"-"`
-}
-
-func (m *NewFileTransfer) Reset()         { *m = NewFileTransfer{} }
-func (m *NewFileTransfer) String() string { return proto.CompactTextString(m) }
-func (*NewFileTransfer) ProtoMessage()    {}
-func (*NewFileTransfer) Descriptor() ([]byte, []int) {
-	return fileDescriptor_9d574f363dd34365, []int{0}
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	FileName    string  `protobuf:"bytes,1,opt,name=fileName,proto3" json:"fileName,omitempty"`       // Name of the file
+	FileType    string  `protobuf:"bytes,2,opt,name=fileType,proto3" json:"fileType,omitempty"`       // String that indicates type of file
+	TransferKey []byte  `protobuf:"bytes,3,opt,name=transferKey,proto3" json:"transferKey,omitempty"` // 256-bit encryption key
+	TransferMac []byte  `protobuf:"bytes,4,opt,name=transferMac,proto3" json:"transferMac,omitempty"` // 256-bit MAC of the entire file
+	NumParts    uint32  `protobuf:"varint,5,opt,name=numParts,proto3" json:"numParts,omitempty"`      // Number of file parts
+	Size        uint32  `protobuf:"varint,6,opt,name=size,proto3" json:"size,omitempty"`              // The size of the file, in bytes
+	Retry       float32 `protobuf:"fixed32,7,opt,name=retry,proto3" json:"retry,omitempty"`           // Determines how many times to retry sending
+	Preview     []byte  `protobuf:"bytes,8,opt,name=preview,proto3" json:"preview,omitempty"`         // A preview of the file
+}
+
+func (x *NewFileTransfer) Reset() {
+	*x = NewFileTransfer{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_ftMessages_proto_msgTypes[0]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
 }
 
-func (m *NewFileTransfer) XXX_Unmarshal(b []byte) error {
-	return xxx_messageInfo_NewFileTransfer.Unmarshal(m, b)
-}
-func (m *NewFileTransfer) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
-	return xxx_messageInfo_NewFileTransfer.Marshal(b, m, deterministic)
-}
-func (m *NewFileTransfer) XXX_Merge(src proto.Message) {
-	xxx_messageInfo_NewFileTransfer.Merge(m, src)
+func (x *NewFileTransfer) String() string {
+	return protoimpl.X.MessageStringOf(x)
 }
-func (m *NewFileTransfer) XXX_Size() int {
-	return xxx_messageInfo_NewFileTransfer.Size(m)
-}
-func (m *NewFileTransfer) XXX_DiscardUnknown() {
-	xxx_messageInfo_NewFileTransfer.DiscardUnknown(m)
+
+func (*NewFileTransfer) ProtoMessage() {}
+
+func (x *NewFileTransfer) ProtoReflect() protoreflect.Message {
+	mi := &file_ftMessages_proto_msgTypes[0]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
 }
 
-var xxx_messageInfo_NewFileTransfer proto.InternalMessageInfo
+// Deprecated: Use NewFileTransfer.ProtoReflect.Descriptor instead.
+func (*NewFileTransfer) Descriptor() ([]byte, []int) {
+	return file_ftMessages_proto_rawDescGZIP(), []int{0}
+}
 
-func (m *NewFileTransfer) GetFileName() string {
-	if m != nil {
-		return m.FileName
+func (x *NewFileTransfer) GetFileName() string {
+	if x != nil {
+		return x.FileName
 	}
 	return ""
 }
 
-func (m *NewFileTransfer) GetFileType() string {
-	if m != nil {
-		return m.FileType
+func (x *NewFileTransfer) GetFileType() string {
+	if x != nil {
+		return x.FileType
 	}
 	return ""
 }
 
-func (m *NewFileTransfer) GetTransferKey() []byte {
-	if m != nil {
-		return m.TransferKey
+func (x *NewFileTransfer) GetTransferKey() []byte {
+	if x != nil {
+		return x.TransferKey
 	}
 	return nil
 }
 
-func (m *NewFileTransfer) GetTransferMac() []byte {
-	if m != nil {
-		return m.TransferMac
+func (x *NewFileTransfer) GetTransferMac() []byte {
+	if x != nil {
+		return x.TransferMac
 	}
 	return nil
 }
 
-func (m *NewFileTransfer) GetNumParts() uint32 {
-	if m != nil {
-		return m.NumParts
+func (x *NewFileTransfer) GetNumParts() uint32 {
+	if x != nil {
+		return x.NumParts
 	}
 	return 0
 }
 
-func (m *NewFileTransfer) GetSize() uint32 {
-	if m != nil {
-		return m.Size
+func (x *NewFileTransfer) GetSize() uint32 {
+	if x != nil {
+		return x.Size
 	}
 	return 0
 }
 
-func (m *NewFileTransfer) GetRetry() float32 {
-	if m != nil {
-		return m.Retry
+func (x *NewFileTransfer) GetRetry() float32 {
+	if x != nil {
+		return x.Retry
 	}
 	return 0
 }
 
-func (m *NewFileTransfer) GetPreview() []byte {
-	if m != nil {
-		return m.Preview
+func (x *NewFileTransfer) GetPreview() []byte {
+	if x != nil {
+		return x.Preview
 	}
 	return nil
 }
 
-func init() {
-	proto.RegisterType((*NewFileTransfer)(nil), "parse.NewFileTransfer")
-}
-
-func init() { proto.RegisterFile("fileTransfer/ftMessages.proto", fileDescriptor_9d574f363dd34365) }
-
-var fileDescriptor_9d574f363dd34365 = []byte{
-	// 213 bytes of a gzipped FileDescriptorProto
-	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x54, 0x90, 0xbd, 0x4a, 0xc7, 0x30,
-	0x14, 0xc5, 0xc9, 0xdf, 0x7e, 0x19, 0xab, 0x42, 0x70, 0xb8, 0x08, 0x42, 0x70, 0xca, 0xa4, 0x83,
-	0x6f, 0xe0, 0xe0, 0x22, 0x2d, 0x12, 0x3a, 0xb9, 0xc5, 0x72, 0x2b, 0x05, 0xdb, 0x86, 0x9b, 0x68,
-	0xa9, 0xef, 0xec, 0x3b, 0x48, 0xa3, 0xad, 0x71, 0xcb, 0xef, 0x9c, 0x93, 0x73, 0xe1, 0xf0, 0xab,
-	0xae, 0x7f, 0xc3, 0x86, 0xcc, 0xe8, 0x3a, 0xa4, 0xdb, 0xce, 0x57, 0xe8, 0x9c, 0x79, 0x45, 0x77,
-	0x63, 0x69, 0xf2, 0x93, 0x48, 0xad, 0x21, 0x87, 0xd7, 0x5f, 0x8c, 0x9f, 0xd7, 0x38, 0x3f, 0x44,
-	0x59, 0x71, 0xc9, 0x8b, 0xf5, 0x6f, 0x6d, 0x06, 0x04, 0x26, 0x99, 0x3a, 0xd6, 0x3b, 0x6f, 0x5e,
-	0xb3, 0x58, 0x84, 0xc3, 0x9f, 0xb7, 0xb2, 0x90, 0xfc, 0xc4, 0xff, 0x76, 0x3c, 0xe2, 0x02, 0x47,
-	0x92, 0xa9, 0x52, 0xc7, 0x52, 0x9c, 0xa8, 0x4c, 0x0b, 0xc9, 0xff, 0x44, 0x65, 0xda, 0xb5, 0x7f,
-	0x7c, 0x1f, 0x9e, 0x0c, 0x79, 0x07, 0xa9, 0x64, 0xea, 0x54, 0xef, 0x2c, 0x04, 0x4f, 0x5c, 0xff,
-	0x89, 0x90, 0x05, 0x3d, 0xbc, 0xc5, 0x05, 0x4f, 0x09, 0x3d, 0x2d, 0x90, 0x4b, 0xa6, 0x0e, 0xfa,
-	0x07, 0x04, 0xf0, 0xdc, 0x12, 0x7e, 0xf4, 0x38, 0x43, 0x11, 0x6e, 0x6c, 0x78, 0x7f, 0xf6, 0x5c,
-	0xc6, 0xbb, 0xbc, 0x64, 0x61, 0x8d, 0xbb, 0xef, 0x00, 0x00, 0x00, 0xff, 0xff, 0xcd, 0x93, 0x73,
-	0x01, 0x2e, 0x01, 0x00, 0x00,
+var File_ftMessages_proto protoreflect.FileDescriptor
+
+var file_ftMessages_proto_rawDesc = []byte{
+	0x0a, 0x10, 0x66, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f,
+	0x74, 0x6f, 0x12, 0x0c, 0x66, 0x69, 0x6c, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72,
+	0x22, 0xed, 0x01, 0x0a, 0x0f, 0x4e, 0x65, 0x77, 0x46, 0x69, 0x6c, 0x65, 0x54, 0x72, 0x61, 0x6e,
+	0x73, 0x66, 0x65, 0x72, 0x12, 0x1a, 0x0a, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65,
+	0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65,
+	0x12, 0x1a, 0x0a, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01,
+	0x28, 0x09, 0x52, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x20, 0x0a, 0x0b,
+	0x74, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x4b, 0x65, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28,
+	0x0c, 0x52, 0x0b, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x4b, 0x65, 0x79, 0x12, 0x20,
+	0x0a, 0x0b, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x4d, 0x61, 0x63, 0x18, 0x04, 0x20,
+	0x01, 0x28, 0x0c, 0x52, 0x0b, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x4d, 0x61, 0x63,
+	0x12, 0x1a, 0x0a, 0x08, 0x6e, 0x75, 0x6d, 0x50, 0x61, 0x72, 0x74, 0x73, 0x18, 0x05, 0x20, 0x01,
+	0x28, 0x0d, 0x52, 0x08, 0x6e, 0x75, 0x6d, 0x50, 0x61, 0x72, 0x74, 0x73, 0x12, 0x12, 0x0a, 0x04,
+	0x73, 0x69, 0x7a, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x73, 0x69, 0x7a, 0x65,
+	0x12, 0x14, 0x0a, 0x05, 0x72, 0x65, 0x74, 0x72, 0x79, 0x18, 0x07, 0x20, 0x01, 0x28, 0x02, 0x52,
+	0x05, 0x72, 0x65, 0x74, 0x72, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x72, 0x65, 0x76, 0x69, 0x65,
+	0x77, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x70, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77,
+	0x42, 0x28, 0x5a, 0x26, 0x67, 0x69, 0x74, 0x6c, 0x61, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x65,
+	0x6c, 0x69, 0x78, 0x78, 0x69, 0x72, 0x2f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x2f, 0x66, 0x69,
+	0x6c, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74,
+	0x6f, 0x33,
+}
+
+var (
+	file_ftMessages_proto_rawDescOnce sync.Once
+	file_ftMessages_proto_rawDescData = file_ftMessages_proto_rawDesc
+)
+
+func file_ftMessages_proto_rawDescGZIP() []byte {
+	file_ftMessages_proto_rawDescOnce.Do(func() {
+		file_ftMessages_proto_rawDescData = protoimpl.X.CompressGZIP(file_ftMessages_proto_rawDescData)
+	})
+	return file_ftMessages_proto_rawDescData
+}
+
+var file_ftMessages_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
+var file_ftMessages_proto_goTypes = []interface{}{
+	(*NewFileTransfer)(nil), // 0: fileTransfer.NewFileTransfer
+}
+var file_ftMessages_proto_depIdxs = []int32{
+	0, // [0:0] is the sub-list for method output_type
+	0, // [0:0] is the sub-list for method input_type
+	0, // [0:0] is the sub-list for extension type_name
+	0, // [0:0] is the sub-list for extension extendee
+	0, // [0:0] is the sub-list for field type_name
+}
+
+func init() { file_ftMessages_proto_init() }
+func file_ftMessages_proto_init() {
+	if File_ftMessages_proto != nil {
+		return
+	}
+	if !protoimpl.UnsafeEnabled {
+		file_ftMessages_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*NewFileTransfer); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+	}
+	type x struct{}
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+			RawDescriptor: file_ftMessages_proto_rawDesc,
+			NumEnums:      0,
+			NumMessages:   1,
+			NumExtensions: 0,
+			NumServices:   0,
+		},
+		GoTypes:           file_ftMessages_proto_goTypes,
+		DependencyIndexes: file_ftMessages_proto_depIdxs,
+		MessageInfos:      file_ftMessages_proto_msgTypes,
+	}.Build()
+	File_ftMessages_proto = out.File
+	file_ftMessages_proto_rawDesc = nil
+	file_ftMessages_proto_goTypes = nil
+	file_ftMessages_proto_depIdxs = nil
 }
diff --git a/fileTransfer/ftMessages.proto b/fileTransfer/ftMessages.proto
index 80547f782b1bb38886c34bc13ed7cf7ebefa8449..f1799036dc31c2e8dae63cf495150cf9a0cd73ce 100644
--- a/fileTransfer/ftMessages.proto
+++ b/fileTransfer/ftMessages.proto
@@ -1,14 +1,15 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 syntax = "proto3";
 
-package parse;
-option go_package = "fileTransfer";
+package fileTransfer;
+
+option go_package = "gitlab.com/elixxir/client/fileTransfer";
 
 // NewFileTransfer is transmitted first on the initialization of a file transfer
 // to inform the receiver about the incoming file.
diff --git a/fileTransfer/generateProto.sh b/fileTransfer/generateProto.sh
deleted file mode 100644
index 45c407448f50766cccb1e8adfee2be839bbf4c4d..0000000000000000000000000000000000000000
--- a/fileTransfer/generateProto.sh
+++ /dev/null
@@ -1,10 +0,0 @@
-#!/bin/bash
-
-#///////////////////////////////////////////////////////////////////////////////
-#/ Copyright © 2020 xx network SEZC                                           //
-#/                                                                            //
-#/ Use of this source code is governed by a license that can be found in the  //
-#/ LICENSE file                                                               //
-#///////////////////////////////////////////////////////////////////////////////
-
-protoc --go_out=paths=source_relative:. fileTransfer/ftMessages.proto
diff --git a/fileTransfer/groupChat/processor.go b/fileTransfer/groupChat/processor.go
index bccc2a6d3f1ff684be8b23fda776e65c71a2e41c..178c774c2eee9e72e8bb5abd11b822e49b7be91e 100644
--- a/fileTransfer/groupChat/processor.go
+++ b/fileTransfer/groupChat/processor.go
@@ -1,8 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package groupChat
diff --git a/fileTransfer/groupChat/send.go b/fileTransfer/groupChat/send.go
index b8d5edaf5fb80811c9a9f0606e430aab812fb727..c57acd848d1862fb51abc1de23e2e4caf66278c4 100644
--- a/fileTransfer/groupChat/send.go
+++ b/fileTransfer/groupChat/send.go
@@ -1,8 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package groupChat
diff --git a/fileTransfer/groupChat/utils_test.go b/fileTransfer/groupChat/utils_test.go
index 38604350816258fbb6e9c85ac882525f78ec3909..76b2ba1285a05381f719089e03bca00248182218 100644
--- a/fileTransfer/groupChat/utils_test.go
+++ b/fileTransfer/groupChat/utils_test.go
@@ -1,8 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package groupChat
@@ -112,12 +112,17 @@ func (m *mockCmix) GetMaxMessageLength() int {
 }
 
 func (m *mockCmix) Send(*id.ID, format.Fingerprint, message.Service, []byte,
-	[]byte, cmix.CMIXParams) (id.Round, ephemeral.Id, error) {
+	[]byte, cmix.CMIXParams) (rounds.Round, ephemeral.Id, error) {
+	panic("implement me")
+}
+
+func (m *mockCmix) SendWithAssembler(recipient *id.ID, assembler cmix.MessageAssembler,
+	cmixParams cmix.CMIXParams) (rounds.Round, ephemeral.Id, error) {
 	panic("implement me")
 }
 
 func (m *mockCmix) SendMany(messages []cmix.TargetedCmixMessage,
-	_ cmix.CMIXParams) (id.Round, []ephemeral.Id, error) {
+	_ cmix.CMIXParams) (rounds.Round, []ephemeral.Id, error) {
 	m.handler.Lock()
 	for _, targetedMsg := range messages {
 		msg := format.NewMessage(m.numPrimeBytes)
@@ -129,7 +134,7 @@ func (m *mockCmix) SendMany(messages []cmix.TargetedCmixMessage,
 			rounds.Round{ID: 42})
 	}
 	m.handler.Unlock()
-	return 42, []ephemeral.Id{}, nil
+	return rounds.Round{ID: 42}, []ephemeral.Id{}, nil
 }
 
 func (m *mockCmix) AddIdentity(*id.ID, time.Time, bool)            { panic("implement me") }
@@ -181,9 +186,8 @@ func (m *mockCmix) NumRegisteredNodes() int        { panic("implement me") }
 func (m *mockCmix) TriggerNodeRegistration(*id.ID) { panic("implement me") }
 
 func (m *mockCmix) GetRoundResults(_ time.Duration,
-	roundCallback cmix.RoundEventCallback, _ ...id.Round) error {
+	roundCallback cmix.RoundEventCallback, _ ...id.Round) {
 	go roundCallback(true, false, map[id.Round]cmix.RoundResult{42: {}})
-	return nil
 }
 
 func (m *mockCmix) LookupHistoricalRound(id.Round, rounds.RoundResultCallback) error {
@@ -230,14 +234,14 @@ func newMockGC(handler *mockGcHandler) *mockGC {
 }
 
 func (m *mockGC) Send(groupID *id.ID, tag string, message []byte) (
-	id.Round, time.Time, group.MessageID, error) {
+	rounds.Round, time.Time, group.MessageID, error) {
 	m.handler.Lock()
 	defer m.handler.Unlock()
 	m.handler.services[tag].Process(groupChat.MessageReceive{
 		GroupID: groupID,
 		Payload: message,
 	}, format.Message{}, receptionID.EphemeralIdentity{}, rounds.Round{})
-	return 0, time.Time{}, group.MessageID{}, nil
+	return rounds.Round{}, time.Time{}, group.MessageID{}, nil
 }
 
 func (m *mockGC) AddService(tag string, p groupChat.Processor) error {
diff --git a/fileTransfer/groupChat/wrapper.go b/fileTransfer/groupChat/wrapper.go
index 63741b74296bc0c6ed6b0a3271324132a06cc8e8..183b6bcde6f88f4326ae6852221156b95915ec63 100644
--- a/fileTransfer/groupChat/wrapper.go
+++ b/fileTransfer/groupChat/wrapper.go
@@ -1,14 +1,15 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package groupChat
 
 import (
 	"github.com/pkg/errors"
+	"gitlab.com/elixxir/client/cmix/rounds"
 	ft "gitlab.com/elixxir/client/fileTransfer"
 	"gitlab.com/elixxir/client/groupChat"
 	ftCrypto "gitlab.com/elixxir/crypto/fileTransfer"
@@ -44,7 +45,7 @@ type Wrapper struct {
 // by the Wrapper for easier testing.
 type gcManager interface {
 	Send(groupID *id.ID, tag string, message []byte) (
-		id.Round, time.Time, group.MessageID, error)
+		rounds.Round, time.Time, group.MessageID, error)
 	AddService(tag string, p groupChat.Processor) error
 }
 
diff --git a/fileTransfer/groupChat/wrapper_test.go b/fileTransfer/groupChat/wrapper_test.go
index f5cfcca4d30e44ec6f1289d3fa87b628869f824e..c6c8f3950441f760a1541a33aacb65cbdf4e96a8 100644
--- a/fileTransfer/groupChat/wrapper_test.go
+++ b/fileTransfer/groupChat/wrapper_test.go
@@ -1,8 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package groupChat
diff --git a/fileTransfer/info.go b/fileTransfer/info.go
index 034acf5327c41540dd80c0b084cb9c84b83a9001..3d840924bc3af3db6de3ae7a0fa50c3dfae9f8e2 100644
--- a/fileTransfer/info.go
+++ b/fileTransfer/info.go
@@ -1,8 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package fileTransfer
diff --git a/fileTransfer/info_test.go b/fileTransfer/info_test.go
index f388eef9d32f6d90ac3d110e2548b80a7752e546..c76c1a5fe2541d37f9e7d15d5733c0176cac8e06 100644
--- a/fileTransfer/info_test.go
+++ b/fileTransfer/info_test.go
@@ -1,8 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package fileTransfer
diff --git a/fileTransfer/interface.go b/fileTransfer/interface.go
index a0f3ed1b142254ab40070ea4b281a2fa1847bfd7..37f7dbf0c85b6bac1ac8e07722f9d71a84788ddb 100644
--- a/fileTransfer/interface.go
+++ b/fileTransfer/interface.go
@@ -1,8 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package fileTransfer
diff --git a/fileTransfer/manager.go b/fileTransfer/manager.go
index a586bad235c4145b1f2042e65511546c951ff284..923218fcd2315dae4541de13dc75827f498b98d7 100644
--- a/fileTransfer/manager.go
+++ b/fileTransfer/manager.go
@@ -1,8 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package fileTransfer
@@ -13,6 +13,7 @@ import (
 	jww "github.com/spf13/jwalterweatherman"
 	"gitlab.com/elixxir/client/cmix"
 	"gitlab.com/elixxir/client/cmix/message"
+	"gitlab.com/elixxir/client/cmix/rounds"
 	"gitlab.com/elixxir/client/e2e"
 	"gitlab.com/elixxir/client/fileTransfer/callbackTracker"
 	"gitlab.com/elixxir/client/fileTransfer/store"
@@ -145,7 +146,7 @@ type FtE2e interface {
 // transfer manager for easier testing.
 type Cmix interface {
 	GetMaxMessageLength() int
-	SendMany(messages []cmix.TargetedCmixMessage, p cmix.CMIXParams) (id.Round,
+	SendMany(messages []cmix.TargetedCmixMessage, p cmix.CMIXParams) (rounds.Round,
 		[]ephemeral.Id, error)
 	AddFingerprint(identity *id.ID, fingerprint format.Fingerprint,
 		mp message.Processor) error
@@ -155,7 +156,7 @@ type Cmix interface {
 	AddHealthCallback(f func(bool)) uint64
 	RemoveHealthCallback(uint64)
 	GetRoundResults(timeout time.Duration,
-		roundCallback cmix.RoundEventCallback, roundList ...id.Round) error
+		roundCallback cmix.RoundEventCallback, roundList ...id.Round)
 }
 
 // Storage interface matches a subset of the storage.Session methods used by the
@@ -215,16 +216,21 @@ func NewManager(params Params, user FtE2e) (FileTransfer, error) {
 // StartProcesses starts the sending threads. Adheres to the xxdk.Service type.
 func (m *manager) StartProcesses() (stoppable.Stoppable, error) {
 	// Construct stoppables
-	multiStop := stoppable.NewMulti(workerPoolStoppable)
+	senderPoolStop := stoppable.NewMulti(workerPoolStoppable)
 	batchBuilderStop := stoppable.NewSingle(batchBuilderThreadStoppable)
 
 	// Start sending threads
-	go m.startSendingWorkerPool(multiStop)
+	// Note that the startSendingWorkerPool already creates thread for every
+	// worker. As a result, there is no need to run it asynchronously. In fact,
+	// running this asynchronously could result in a race condition where
+	// some worker threads are not added to senderPoolStop before that stoppable
+	// is added to the multiStoppable.
+	m.startSendingWorkerPool(senderPoolStop)
 	go m.batchBuilderThread(batchBuilderStop)
 
 	// Create a multi stoppable
 	multiStoppable := stoppable.NewMulti(fileTransferStoppable)
-	multiStoppable.Add(multiStop)
+	multiStoppable.Add(senderPoolStop)
 	multiStoppable.Add(batchBuilderStop)
 
 	return multiStoppable, nil
diff --git a/fileTransfer/manager_test.go b/fileTransfer/manager_test.go
index 425e26ad03448690d98a7b31d200634960fb7fca..c2bee63b482f66b057625c06d2c53a601f1f6620 100644
--- a/fileTransfer/manager_test.go
+++ b/fileTransfer/manager_test.go
@@ -1,8 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package fileTransfer
diff --git a/fileTransfer/params.go b/fileTransfer/params.go
index fd756a6c8f1318df7200ee149ce17e24457dfe34..e0ecffed8ed3d040cc4c2f4a54d04f4b34f26b83 100644
--- a/fileTransfer/params.go
+++ b/fileTransfer/params.go
@@ -1,8 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package fileTransfer
diff --git a/fileTransfer/params_test.go b/fileTransfer/params_test.go
index 965ff70f98185c6fb6b686d967c91d5e0610f28d..e60c9a6381c75881c049d6b538f4b3587aac4ece 100644
--- a/fileTransfer/params_test.go
+++ b/fileTransfer/params_test.go
@@ -1,8 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package fileTransfer
diff --git a/fileTransfer/partTracker.go b/fileTransfer/partTracker.go
index 1288c7a16482fecec864a5cfa236b373c1020d3e..1d432c50fe5756b1a1ce7af3e9440888bcde2396 100644
--- a/fileTransfer/partTracker.go
+++ b/fileTransfer/partTracker.go
@@ -1,8 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package fileTransfer
diff --git a/fileTransfer/processor.go b/fileTransfer/processor.go
index a1bb17db81a04c8dec2ab894e17a9f91fa82f6de..adcf474a77ffebc499abbbceeb759ba0b909ca64 100644
--- a/fileTransfer/processor.go
+++ b/fileTransfer/processor.go
@@ -1,8 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package fileTransfer
diff --git a/fileTransfer/send.go b/fileTransfer/send.go
index 708bbf32e755779457dcc28d3fc54754f425a819..fb4bbddb36c66d5a7f5ebd0bfff9d7b160bbdc91 100644
--- a/fileTransfer/send.go
+++ b/fileTransfer/send.go
@@ -1,8 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package fileTransfer
@@ -62,9 +62,10 @@ func (m *manager) startSendingWorkerPool(multiStop *stoppable.Multi) {
 
 	for i := 0; i < workerPoolThreads; i++ {
 		stop := stoppable.NewSingle(sendThreadStoppableName + strconv.Itoa(i))
-		multiStop.Add(stop)
 		go m.sendingThread(stop)
+		multiStop.Add(stop)
 	}
+
 }
 
 // sendingThread sends part packets that become available oin the send queue.
@@ -74,8 +75,8 @@ func (m *manager) sendingThread(stop *stoppable.Single) {
 	for {
 		select {
 		case <-stop.Quit():
-			jww.DEBUG.Printf("[FT] Stopping file part sending thread: " +
-				"stoppable triggered.")
+			jww.DEBUG.Printf("[FT] Stopping file part sending thread (%s): "+
+				"stoppable triggered.", stop.Name())
 			m.cmix.RemoveHealthCallback(healthChanID)
 			stop.ToStopped()
 			return
@@ -134,8 +135,8 @@ func (m *manager) sendCmix(packet []store.Part) {
 		}
 	}
 
-	err = m.cmix.GetRoundResults(
-		roundResultsTimeout, m.roundResultsCallback(validParts), rid)
+	m.cmix.GetRoundResults(
+		roundResultsTimeout, m.roundResultsCallback(validParts), rid.ID)
 }
 
 // roundResultsCallback generates a network.RoundEventCallback that handles
diff --git a/fileTransfer/sentRoundTracker/sentRoundTracker.go b/fileTransfer/sentRoundTracker/sentRoundTracker.go
index 68511497dad8fbb2d7f3a3417c4d3873997a7c58..6b1a8667d01f19fa2151d536dd872304d55d6978 100644
--- a/fileTransfer/sentRoundTracker/sentRoundTracker.go
+++ b/fileTransfer/sentRoundTracker/sentRoundTracker.go
@@ -1,8 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package sentRoundTracker
diff --git a/fileTransfer/sentRoundTracker/sentRoundTracker_test.go b/fileTransfer/sentRoundTracker/sentRoundTracker_test.go
index 90876842d6408cee151bf9d8cdb38598e276135c..3485da2c19af89995183cae3a253fb6d90284e9d 100644
--- a/fileTransfer/sentRoundTracker/sentRoundTracker_test.go
+++ b/fileTransfer/sentRoundTracker/sentRoundTracker_test.go
@@ -1,8 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package sentRoundTracker
diff --git a/fileTransfer/store/cypher/cypher.go b/fileTransfer/store/cypher/cypher.go
index c1926c9be6f9c79b9af0b7b05d8f9010d53efdcb..1a37c427342da0deb76ff1ba1d1e16fcba44b063 100644
--- a/fileTransfer/store/cypher/cypher.go
+++ b/fileTransfer/store/cypher/cypher.go
@@ -1,8 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package cypher
diff --git a/fileTransfer/store/cypher/cypher_test.go b/fileTransfer/store/cypher/cypher_test.go
index b3700090322106e817e6c30c1bcceb69eca1df4e..6bf07b1e036cb8054789a5fbc9aa472b722e4df2 100644
--- a/fileTransfer/store/cypher/cypher_test.go
+++ b/fileTransfer/store/cypher/cypher_test.go
@@ -1,8 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package cypher
diff --git a/fileTransfer/store/cypher/manager.go b/fileTransfer/store/cypher/manager.go
index be1662d2da1dd4eb7062e990b31dc341fa3eae92..88d67d7c4488b2b0122ccb9808ed52e2a4fc97b0 100644
--- a/fileTransfer/store/cypher/manager.go
+++ b/fileTransfer/store/cypher/manager.go
@@ -1,8 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package cypher
@@ -164,7 +164,7 @@ func saveKey(key *ftCrypto.TransferKey, kv *versioned.KV) error {
 		Data:      key.Bytes(),
 	}
 
-	return kv.Set(cypherManagerKeyStoreKey, cypherManagerKeyStoreVersion, obj)
+	return kv.Set(cypherManagerKeyStoreKey, obj)
 }
 
 // loadKey loads the transfer key from storage.
diff --git a/fileTransfer/store/cypher/manager_test.go b/fileTransfer/store/cypher/manager_test.go
index c1857b7ae4920b0c26decdfb98752b0fc59acf74..f88bc48390f09fc22472529e972daebae5c63860 100644
--- a/fileTransfer/store/cypher/manager_test.go
+++ b/fileTransfer/store/cypher/manager_test.go
@@ -1,8 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package cypher
diff --git a/fileTransfer/store/fileMessage/fileMessage.go b/fileTransfer/store/fileMessage/fileMessage.go
index d1d0e107b33d6fe9c08e685461d1269e0bcc7753..c14bf742d34ea7c7e007c400b9fd7c7972324d6d 100644
--- a/fileTransfer/store/fileMessage/fileMessage.go
+++ b/fileTransfer/store/fileMessage/fileMessage.go
@@ -1,8 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package fileMessage
diff --git a/fileTransfer/store/fileMessage/fileMessage_test.go b/fileTransfer/store/fileMessage/fileMessage_test.go
index b7ac5e0e60d50f4f5be80bf2522db1e010e2de4f..240ae1af5fd0b5a175df91f1d7d2a2173422a14a 100644
--- a/fileTransfer/store/fileMessage/fileMessage_test.go
+++ b/fileTransfer/store/fileMessage/fileMessage_test.go
@@ -1,8 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package fileMessage
diff --git a/fileTransfer/store/part.go b/fileTransfer/store/part.go
index c382699695cda68c24ae417721660baae162757d..742d5a391c4b38ac2cfbb6998598d606ae0d1e50 100644
--- a/fileTransfer/store/part.go
+++ b/fileTransfer/store/part.go
@@ -1,8 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package store
diff --git a/fileTransfer/store/part_test.go b/fileTransfer/store/part_test.go
index ea71d299e44fbf66f0309e646dbba4f8e14a6596..871e3d10bd9b6acdd5e5b0f122fae449e0326e50 100644
--- a/fileTransfer/store/part_test.go
+++ b/fileTransfer/store/part_test.go
@@ -1,8 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package store
diff --git a/fileTransfer/store/received.go b/fileTransfer/store/received.go
index 8522f6a86abad452e0c49e871e64d54ce139c8e7..189025a711b89537022a99ec72d19eaf98e63c91 100644
--- a/fileTransfer/store/received.go
+++ b/fileTransfer/store/received.go
@@ -1,8 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package store
@@ -13,7 +13,6 @@ import (
 	jww "github.com/spf13/jwalterweatherman"
 	"gitlab.com/elixxir/client/storage/versioned"
 	ftCrypto "gitlab.com/elixxir/crypto/fileTransfer"
-	"gitlab.com/elixxir/ekv"
 	"gitlab.com/xx_network/primitives/netTime"
 	"sync"
 )
@@ -56,7 +55,7 @@ func NewOrLoadReceived(kv *versioned.KV) (*Received, []*ReceivedTransfer, error)
 
 	obj, err := s.kv.Get(receivedTransfersStoreKey, receivedTransfersStoreVersion)
 	if err != nil {
-		if ekv.Exists(err) {
+		if kv.Exists(err) {
 			return nil, nil, errors.Errorf(errLoadReceived, err)
 		} else {
 			return s, nil, nil
@@ -157,7 +156,7 @@ func (r *Received) save() error {
 		Data:      data,
 	}
 
-	return r.kv.Set(receivedTransfersStoreKey, receivedTransfersStoreVersion, obj)
+	return r.kv.Set(receivedTransfersStoreKey, obj)
 }
 
 // marshalReceivedTransfersMap serialises the list of transfer IDs from a
diff --git a/fileTransfer/store/receivedTransfer.go b/fileTransfer/store/receivedTransfer.go
index db6f54264a4094e22b53b32e7f763b700adc3827..5ae7a07d52e1ecc73ba9fb6582ee2e3094730fcb 100644
--- a/fileTransfer/store/receivedTransfer.go
+++ b/fileTransfer/store/receivedTransfer.go
@@ -1,8 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package store
@@ -339,7 +339,7 @@ func (rt *ReceivedTransfer) save() error {
 	}
 
 	// Save versioned object
-	return rt.kv.Set(receivedTransferStoreKey, receivedTransferStoreVersion, vo)
+	return rt.kv.Set(receivedTransferStoreKey, vo)
 }
 
 // receivedTransferDisk structure is used to marshal and unmarshal
@@ -385,7 +385,7 @@ func savePart(part []byte, partNum int, kv *versioned.KV) error {
 		Data:      part,
 	}
 
-	return kv.Set(makeReceivedPartKey(partNum), receivedPartStoreVersion, obj)
+	return kv.Set(makeReceivedPartKey(partNum), obj)
 }
 
 // loadPart loads the part with the given part number from storage.
diff --git a/fileTransfer/store/receivedTransfer_test.go b/fileTransfer/store/receivedTransfer_test.go
index e1a32e74db61be43052b8dae03a358ec9c014c5c..b68e0b071480d9e84569c745a0024e42d07838b8 100644
--- a/fileTransfer/store/receivedTransfer_test.go
+++ b/fileTransfer/store/receivedTransfer_test.go
@@ -1,8 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package store
diff --git a/fileTransfer/store/received_test.go b/fileTransfer/store/received_test.go
index 4aa468f84055ed50f6b8272a858697273f20efd3..3bcba24b6e32847945ce6d10961517aa14dded3a 100644
--- a/fileTransfer/store/received_test.go
+++ b/fileTransfer/store/received_test.go
@@ -1,8 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package store
@@ -204,8 +204,8 @@ func TestReceived_save(t *testing.T) {
 	kv := versioned.NewKV(ekv.MakeMemstore())
 	r, _, _ := NewOrLoadReceived(kv)
 	r.transfers = map[ftCrypto.TransferID]*ReceivedTransfer{
-		ftCrypto.TransferID{0}: nil, ftCrypto.TransferID{1}: nil,
-		ftCrypto.TransferID{2}: nil, ftCrypto.TransferID{3}: nil,
+		{0}: nil, {1}: nil,
+		{2}: nil, {3}: nil,
 	}
 
 	err := r.save()
diff --git a/fileTransfer/store/sent.go b/fileTransfer/store/sent.go
index 7873d5b469bafc8666b0951d55d7852aff0c1ae6..a7f89a598dd79ec14b421b0101d0dae5ab7e05cf 100644
--- a/fileTransfer/store/sent.go
+++ b/fileTransfer/store/sent.go
@@ -1,8 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package store
@@ -13,7 +13,6 @@ import (
 	jww "github.com/spf13/jwalterweatherman"
 	"gitlab.com/elixxir/client/storage/versioned"
 	ftCrypto "gitlab.com/elixxir/crypto/fileTransfer"
-	"gitlab.com/elixxir/ekv"
 	"gitlab.com/xx_network/primitives/id"
 	"gitlab.com/xx_network/primitives/netTime"
 	"sync"
@@ -58,7 +57,7 @@ func NewOrLoadSent(kv *versioned.KV) (*Sent, []Part, error) {
 
 	obj, err := s.kv.Get(sentTransfersStoreKey, sentTransfersStoreVersion)
 	if err != nil {
-		if !ekv.Exists(err) {
+		if !kv.Exists(err) {
 			// Return the new Sent if none exists in storage
 			return s, nil, nil
 		} else {
@@ -165,7 +164,7 @@ func (s *Sent) save() error {
 		Data:      data,
 	}
 
-	return s.kv.Set(sentTransfersStoreKey, sentTransfersStoreVersion, obj)
+	return s.kv.Set(sentTransfersStoreKey, obj)
 }
 
 // marshalSentTransfersMap serialises the list of transfer IDs from a
diff --git a/fileTransfer/store/sentTransfer.go b/fileTransfer/store/sentTransfer.go
index 83b9594fb0a6764ace36514d86e38cfcb0b985b8..39e826ccb7bd3c4f47e4c9c7fbc436fdc8cc46e7 100644
--- a/fileTransfer/store/sentTransfer.go
+++ b/fileTransfer/store/sentTransfer.go
@@ -1,8 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package store
@@ -346,7 +346,7 @@ func (st *SentTransfer) save() error {
 		Data:      data,
 	}
 
-	return st.kv.Set(sentTransferStoreKey, sentTransferStoreVersion, obj)
+	return st.kv.Set(sentTransferStoreKey, obj)
 }
 
 // sentTransferDisk structure is used to marshal and unmarshal SentTransfer
diff --git a/fileTransfer/store/sentTransfer_test.go b/fileTransfer/store/sentTransfer_test.go
index a9366ce8057dbaac8641bcd9132d54e2dfcb41f4..20f1428a57759e94f86c22e811f25b2c4dfd5eff 100644
--- a/fileTransfer/store/sentTransfer_test.go
+++ b/fileTransfer/store/sentTransfer_test.go
@@ -1,8 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package store
diff --git a/fileTransfer/store/sent_test.go b/fileTransfer/store/sent_test.go
index f07a5996c2ba9844faeeffecaed6c171eecb4851..f3f24e43e4670b3d317d43d3e88a6c21c2ae4ace 100644
--- a/fileTransfer/store/sent_test.go
+++ b/fileTransfer/store/sent_test.go
@@ -1,8 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package store
@@ -225,8 +225,8 @@ func TestSent_save(t *testing.T) {
 	kv := versioned.NewKV(ekv.MakeMemstore())
 	s, _, _ := NewOrLoadSent(kv)
 	s.transfers = map[ftCrypto.TransferID]*SentTransfer{
-		ftCrypto.TransferID{0}: nil, ftCrypto.TransferID{1}: nil,
-		ftCrypto.TransferID{2}: nil, ftCrypto.TransferID{3}: nil,
+		{0}: nil, {1}: nil,
+		{2}: nil, {3}: nil,
 	}
 
 	err := s.save()
diff --git a/fileTransfer/store/transferStatus.go b/fileTransfer/store/transferStatus.go
index 4055f622a58bb1daac519c103abf9315e439acc4..7f49e0612ac9556c77f47634056ccb80e12ead7b 100644
--- a/fileTransfer/store/transferStatus.go
+++ b/fileTransfer/store/transferStatus.go
@@ -1,8 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package store
diff --git a/fileTransfer/store/transferStatus_test.go b/fileTransfer/store/transferStatus_test.go
index a54878295b992b7faefecd3f9e66f1c78561d976..4fbcb69cb3951536a4bdee55800bf576a3277d29 100644
--- a/fileTransfer/store/transferStatus_test.go
+++ b/fileTransfer/store/transferStatus_test.go
@@ -1,8 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package store
diff --git a/fileTransfer/utils_test.go b/fileTransfer/utils_test.go
index df51d90ddaa113ce471244217d567fa3868a1883..96c400a9dfdaa63cb84242b083e41325c25606d1 100644
--- a/fileTransfer/utils_test.go
+++ b/fileTransfer/utils_test.go
@@ -1,8 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package fileTransfer
@@ -166,12 +166,17 @@ func (m *mockCmix) GetMaxMessageLength() int {
 }
 
 func (m *mockCmix) Send(*id.ID, format.Fingerprint, message.Service, []byte,
-	[]byte, cmix.CMIXParams) (id.Round, ephemeral.Id, error) {
+	[]byte, cmix.CMIXParams) (rounds.Round, ephemeral.Id, error) {
+	panic("implement me")
+}
+
+func (m *mockCmix) SendWithAssembler(recipient *id.ID, assembler cmix.MessageAssembler,
+	cmixParams cmix.CMIXParams) (rounds.Round, ephemeral.Id, error) {
 	panic("implement me")
 }
 
 func (m *mockCmix) SendMany(messages []cmix.TargetedCmixMessage,
-	_ cmix.CMIXParams) (id.Round, []ephemeral.Id, error) {
+	_ cmix.CMIXParams) (rounds.Round, []ephemeral.Id, error) {
 	m.handler.Lock()
 	defer m.handler.Unlock()
 	round := m.round
@@ -185,7 +190,7 @@ func (m *mockCmix) SendMany(messages []cmix.TargetedCmixMessage,
 			receptionID.EphemeralIdentity{Source: targetedMsg.Recipient},
 			rounds.Round{ID: round})
 	}
-	return round, []ephemeral.Id{}, nil
+	return rounds.Round{ID: round}, []ephemeral.Id{}, nil
 }
 
 func (m *mockCmix) AddIdentity(*id.ID, time.Time, bool)            { panic("implement me") }
@@ -237,9 +242,8 @@ func (m *mockCmix) NumRegisteredNodes() int        { panic("implement me") }
 func (m *mockCmix) TriggerNodeRegistration(*id.ID) { panic("implement me") }
 
 func (m *mockCmix) GetRoundResults(_ time.Duration,
-	roundCallback cmix.RoundEventCallback, rids ...id.Round) error {
+	roundCallback cmix.RoundEventCallback, rids ...id.Round) {
 	go roundCallback(true, false, map[id.Round]cmix.RoundResult{rids[0]: {}})
-	return nil
 }
 
 func (m *mockCmix) LookupHistoricalRound(id.Round, rounds.RoundResultCallback) error {
diff --git a/go.mod b/go.mod
index 372fb69b5f827d9103636d2aaf5d5f42724216a3..227defa233b7142edb35eda25b490b34b146281f 100644
--- a/go.mod
+++ b/go.mod
@@ -8,38 +8,50 @@ require (
 	github.com/golang/protobuf v1.5.2
 	github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646
 	github.com/pkg/errors v0.9.1
+	github.com/pkg/profile v1.6.0
 	github.com/spf13/cobra v1.5.0
 	github.com/spf13/jwalterweatherman v1.1.0
 	github.com/spf13/viper v1.12.0
+	github.com/stretchr/testify v1.8.0
 	gitlab.com/elixxir/bloomfilter v0.0.0-20211222005329-7d931ceead6f
-	gitlab.com/elixxir/comms v0.0.4-0.20220805121030-b95005ac4528
-	gitlab.com/elixxir/crypto v0.0.7-0.20220808171640-473891de4c46
-	gitlab.com/elixxir/ekv v0.1.7
-	gitlab.com/elixxir/primitives v0.0.3-0.20220606195757-40f7a589347f
-	gitlab.com/xx_network/comms v0.0.4-0.20220630163702-f3d372ef6acd
-	gitlab.com/xx_network/crypto v0.0.5-0.20220729193517-1e5e96f39f6e
-	gitlab.com/xx_network/primitives v0.0.4-0.20221010192422-3479f09b7769
+	gitlab.com/elixxir/comms v0.0.4-0.20221005205938-10f2defa5b33
+	gitlab.com/elixxir/crypto v0.0.7-0.20221003185354-b091598d2322
+	gitlab.com/elixxir/ekv v0.2.1
+	gitlab.com/elixxir/primitives v0.0.3-0.20220901220638-1acc75fabdc6
+	gitlab.com/xx_network/comms v0.0.4-0.20221005205845-b34d538ffd85
+	gitlab.com/xx_network/crypto v0.0.5-0.20220913213008-98764f5b3287
+	gitlab.com/xx_network/primitives v0.0.4-0.20220809193445-9fc0a5209548
 	go.uber.org/ratelimit v0.2.0
 	golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa
-	golang.org/x/net v0.0.0-20220802222814-0bcc04d9c69b
-	google.golang.org/grpc v1.48.0
+	golang.org/x/net v0.0.0-20220822230855-b0a4917ee28c
+	google.golang.org/grpc v1.49.0
 	google.golang.org/protobuf v1.28.1
 )
 
 require (
+	git.xx.network/elixxir/grpc-web-go-client v0.0.0-20220908170150-ef04339ffe65 // indirect
 	github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129 // indirect
 	github.com/badoux/checkmail v1.2.1 // indirect
+	github.com/cenkalti/backoff/v4 v4.1.3 // indirect
+	github.com/davecgh/go-spew v1.1.1 // indirect
+	github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f // indirect
 	github.com/elliotchance/orderedmap v1.4.0 // indirect
 	github.com/fsnotify/fsnotify v1.5.4 // indirect
+	github.com/gorilla/websocket v1.5.0 // indirect
 	github.com/hashicorp/hcl v1.0.0 // indirect
+	github.com/improbable-eng/grpc-web v0.15.0 // indirect
 	github.com/inconshreveable/mousetrap v1.0.0 // indirect
+	github.com/klauspost/compress v1.11.7 // indirect
 	github.com/klauspost/cpuid/v2 v2.1.0 // indirect
 	github.com/magiconair/properties v1.8.6 // indirect
 	github.com/mitchellh/go-homedir v1.1.0 // indirect
 	github.com/mitchellh/mapstructure v1.5.0 // indirect
 	github.com/pelletier/go-toml v1.9.5 // indirect
 	github.com/pelletier/go-toml/v2 v2.0.2 // indirect
+	github.com/pmezard/go-difflib v1.0.0 // indirect
+	github.com/rs/cors v1.8.2 // indirect
 	github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e // indirect
+	github.com/soheilhy/cmux v0.1.5 // indirect
 	github.com/spf13/afero v1.9.2 // indirect
 	github.com/spf13/cast v1.5.0 // indirect
 	github.com/spf13/pflag v1.0.5 // indirect
@@ -49,10 +61,12 @@ require (
 	github.com/tyler-smith/go-bip39 v1.1.0 // indirect
 	github.com/zeebo/blake3 v0.2.3 // indirect
 	gitlab.com/xx_network/ring v0.0.3-0.20220222211904-da613960ad93 // indirect
+	go.uber.org/atomic v1.10.0 // indirect
 	golang.org/x/sys v0.0.0-20220731174439-a90be440212d // indirect
 	golang.org/x/text v0.3.7 // indirect
-	google.golang.org/genproto v0.0.0-20220802133213-ce4fa296bf78 // indirect
+	google.golang.org/genproto v0.0.0-20220822174746-9e6da59bd2fc // indirect
 	gopkg.in/ini.v1 v1.66.6 // indirect
 	gopkg.in/yaml.v2 v2.4.0 // indirect
 	gopkg.in/yaml.v3 v3.0.1 // indirect
+	nhooyr.io/websocket v1.8.7 // indirect
 )
diff --git a/go.sum b/go.sum
index 2e2ecf7e928609c7877100b0f1597c23f6a16bb3..398547585158c8b9af50df15e192eba16eca6239 100644
--- a/go.sum
+++ b/go.sum
@@ -54,10 +54,17 @@ cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RX
 cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
 cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo=
 dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
+git.xx.network/elixxir/grpc-web-go-client v0.0.0-20220908170150-ef04339ffe65 h1:ksB3ZiMeFplqlaCjMDqKegbGzDZdS5pU0Z5GgFeBdZ0=
+git.xx.network/elixxir/grpc-web-go-client v0.0.0-20220908170150-ef04339ffe65/go.mod h1:uFKw2wmgtlYMdiIm08dM0Vj4XvX9ZKVCj71c8O7SAPo=
 github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
 github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
 github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
+github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
 github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
+github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
+github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
+github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g=
+github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c=
 github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
 github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
 github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
@@ -66,11 +73,17 @@ github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk5
 github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129 h1:MzBOUgng9orim59UnfUTLRjMpd09C5uEVQ6RPGeCaVI=
 github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129/go.mod h1:rFgpPQZYZ8vdbc+48xibu8ALc3yeyd64IhHS+PU6Yyg=
 github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
+github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
+github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
 github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
 github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
 github.com/armon/go-metrics v0.3.10/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc=
 github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
 github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
+github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A=
+github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU=
+github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
+github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g=
 github.com/badoux/checkmail v1.2.1 h1:TzwYx5pnsV6anJweMx2auXdekBwGr/yt1GgalIx9nBQ=
 github.com/badoux/checkmail v1.2.1/go.mod h1:XroCOBU5zzZJcLvgwU15I+2xXyCdTWXyR9MGfRhBYy0=
 github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
@@ -79,6 +92,12 @@ github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6r
 github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
 github.com/bwesterb/go-ristretto v1.2.0/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0=
 github.com/bwesterb/go-ristretto v1.2.1/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0=
+github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ=
+github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4=
+github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
+github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw=
+github.com/cenkalti/backoff/v4 v4.1.3 h1:cFAlzYUlVYDysBEH2T5hyJZMh3+5+WCBvSnK6Q8UtC4=
+github.com/cenkalti/backoff/v4 v4.1.3/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw=
 github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
 github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
 github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
@@ -87,6 +106,7 @@ github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5P
 github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
 github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag=
 github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I=
+github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE=
 github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
 github.com/cloudflare/circl v1.1.0/go.mod h1:prBCrKB9DV4poKZY1l9zBXg2QJY7mvgRvtMxxK7fi4I=
 github.com/cloudflare/circl v1.2.0 h1:NheeISPSUcYftKlfrLuOo4T62FkmD4t4jviLfFFYaec=
@@ -100,16 +120,32 @@ github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWH
 github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
 github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
 github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
+github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
+github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
+github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
 github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
+github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
 github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
+github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
+github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
 github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
+github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
 github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f h1:U5y3Y5UE0w7amNe7Z5G/twsBW0KEalRQXZzf8ufSh9I=
+github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f/go.mod h1:xH/i4TFMt8koVQZ6WFms69WAsDWr2XsYL3Hkl7jkoLE=
+github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
+github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
 github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
+github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
+github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
+github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
+github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
 github.com/elliotchance/orderedmap v1.4.0 h1:wZtfeEONCbx6in1CZyE6bELEt/vFayMvsxqI5SgsR+A=
 github.com/elliotchance/orderedmap v1.4.0/go.mod h1:wsDwEaX5jEoyhbs7x93zk2H/qv0zwuhg4inXhDkYqys=
+github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g=
 github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
 github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
 github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
@@ -123,28 +159,54 @@ github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7
 github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
 github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
 github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
+github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4=
+github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20=
 github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE=
 github.com/frankban/quicktest v1.14.3/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps=
+github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
 github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
 github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI=
 github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU=
 github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
+github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
+github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
+github.com/gin-gonic/gin v1.6.3 h1:ahKqKTFpO5KTPHxWZjEdPScmYaGtLo8Y4DMHoEsnp14=
+github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M=
 github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
 github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
 github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
 github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
 github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
+github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o=
 github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
 github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
 github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
 github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
+github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
+github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q=
+github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
+github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no=
+github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
+github.com/go-playground/validator/v10 v10.2.0 h1:KgJ0snyC2R9VXYN2rneOtQcw5aHQB1Vv0sFl1UcHBOY=
+github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI=
+github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
 github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
+github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee h1:s+21KNqlpePfkah2I+gwHF8xmJWRjooY+5248k6m4A0=
+github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo=
+github.com/gobwas/pool v0.2.0 h1:QEmUOlnSjWtnpRGHF3SauEiOsy82Cup83Vf2LcMlnc8=
+github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
+github.com/gobwas/ws v1.0.2 h1:CoAavW/wd/kulfZmSIBt6p24n4j7tHgNVCjsfHVNUbo=
+github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM=
 github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
+github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s=
 github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
+github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
+github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
 github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
 github.com/golang-collections/collections v0.0.0-20130729185459-604e922904d3 h1:zN2lZNZRflqFyxVaTIU61KNKQ9C0055u9CAfpmqUvo4=
 github.com/golang-collections/collections v0.0.0-20130729185459-604e922904d3/go.mod h1:nPpo7qLxd6XL3hWJG/O60sR8ZKfMCiIoNap5GvD12KU=
 github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
+github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
 github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
 github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
 github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
@@ -176,6 +238,7 @@ github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaS
 github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM=
 github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
 github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
+github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
 github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
 github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
 github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
@@ -215,6 +278,7 @@ github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLe
 github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
 github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
 github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
+github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
 github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
 github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
 github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
@@ -224,9 +288,22 @@ github.com/googleapis/gax-go/v2 v2.2.0/go.mod h1:as02EH8zWkzwUoLbBaFeQ+arQaj/Oth
 github.com/googleapis/gax-go/v2 v2.3.0/go.mod h1:b8LNqSzNabLiUpXKkY7HAR5jr6bIT99EXz9pXxye9YM=
 github.com/googleapis/gax-go/v2 v2.4.0/go.mod h1:XOTVJ59hdnfJLIP/dh8n5CGryZR2LxK9wbMD5+iXC6c=
 github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g=
+github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
+github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
+github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
+github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
+github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
+github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
+github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
+github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
+github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
+github.com/grpc-ecosystem/go-grpc-middleware v1.2.2/go.mod h1:EaizFBKfUKtMIF5iaDEhniwNedqGo9FuLFzppDr3uwI=
 github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
+github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
 github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
+github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE=
 github.com/hashicorp/consul/api v1.12.0/go.mod h1:6pVBMo0ebnYdt2S3H87XhekM/HHrUoTD2XXb/VrZVy0=
+github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
 github.com/hashicorp/consul/sdk v0.8.0/go.mod h1:GBvyrGALthsZObzUGsfgHZQDXjg4lOjagTIwIR1vPms=
 github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
 github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
@@ -240,37 +317,63 @@ github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iP
 github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
 github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA=
 github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs=
+github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
 github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8=
 github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
 github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
 github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
 github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
+github.com/hashicorp/go-version v1.0.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
+github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
+github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
 github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
 github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
 github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
 github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
 github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
 github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
+github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
 github.com/hashicorp/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc=
+github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
 github.com/hashicorp/memberlist v0.3.0/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE=
+github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
 github.com/hashicorp/serf v0.9.6/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4=
 github.com/hashicorp/serf v0.9.7/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4=
+github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
+github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg=
 github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
 github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
+github.com/improbable-eng/grpc-web v0.12.0/go.mod h1:6hRR09jOEG81ADP5wCQju1z71g6OL4eEvELdran/3cs=
+github.com/improbable-eng/grpc-web v0.14.1/go.mod h1:zEjGHa8DAlkoOXmswrNvhUGEYQA9UI7DhrGeHR1DMGU=
+github.com/improbable-eng/grpc-web v0.15.0 h1:BN+7z6uNXZ1tQGcNAuaU1YjsLTApzkjt2tzCixLaUPQ=
+github.com/improbable-eng/grpc-web v0.15.0/go.mod h1:1sy9HKV4Jt9aEs9JSnkWlRJPuPtwNr0l57L4f878wP8=
 github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
 github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
+github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo=
+github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
+github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
 github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
 github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
+github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
+github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
 github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
 github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
 github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
+github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
 github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
 github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
 github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
+github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
 github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
 github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
+github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
 github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
 github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
+github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
+github.com/klauspost/compress v1.11.7 h1:0hzRabrMN4tSTvMfnL3SCv1ZGeAP23ynzodBgaHeMeg=
+github.com/klauspost/compress v1.11.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
+github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
+github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
 github.com/klauspost/cpuid/v2 v2.0.12/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c=
 github.com/klauspost/cpuid/v2 v2.1.0 h1:eyi1Ad2aNJMW95zcSbmGg7Cg6cq3ADwLpMAP96d8rF0=
 github.com/klauspost/cpuid/v2 v2.1.0/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
@@ -287,8 +390,21 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
 github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
 github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
 github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
+github.com/ktr0731/dept v0.1.3/go.mod h1:b1EtCEjbjGShAfhZue+BrFKTG7sQmK7aSD7Q6VcGvO0=
+github.com/ktr0731/go-multierror v0.0.0-20171204182908-b7773ae21874/go.mod h1:ZWayuE/hCzOD96CJizvcYnqrbmTC7RAG332yNtlKj6w=
+github.com/ktr0731/grpc-test v0.1.4/go.mod h1:v47616grayBYXQveGWxO3OwjLB3nEEnHsZuMTc73FM0=
+github.com/ktr0731/grpc-test v0.1.12 h1:Yha+zH2hB48huOfbsEMfyG7FeHCrVWq4fYmHfr3iH3U=
+github.com/ktr0731/grpc-test v0.1.12/go.mod h1:AP4+ZrqSzdDaUNhAsp2fye06MXO2fdYY6YQJifb588M=
+github.com/ktr0731/grpc-web-go-client v0.2.8 h1:nUf9p+YWirmFwmH0mwtAWhuXvzovc+/3C/eAY2Fshnk=
+github.com/ktr0731/grpc-web-go-client v0.2.8/go.mod h1:1Iac8gFJvC/DRfZoGnFZsfEbEq/wQFK+2Ve1o3pHkCQ=
+github.com/ktr0731/modfile v1.11.2/go.mod h1:LzNwnHJWHbuDh3BO17lIqzqDldXqGu1HCydWH3SinE0=
+github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y=
+github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
+github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM=
+github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4=
 github.com/liyue201/goqr v0.0.0-20200803022322-df443203d4ea h1:uyJ13zfy6l79CM3HnVhDalIyZ4RJAyVfDrbnfFeJoC4=
 github.com/liyue201/goqr v0.0.0-20200803022322-df443203d4ea/go.mod h1:w4pGU9PkiX2hAWyF0yuHEHmYTQFAd6WHzp6+IY7JVjE=
+github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ=
 github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo=
 github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
 github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
@@ -297,96 +413,176 @@ github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope
 github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
 github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
 github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
+github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
 github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
 github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
 github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
 github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
+github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
 github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
+github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
 github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
+github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
 github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso=
 github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI=
+github.com/minio/sha256-simd v1.0.0/go.mod h1:OuYzVNI5vcoYIAmbIvHPl3N3jUzVedXbKy5RFepssQM=
+github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
 github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI=
+github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw=
+github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
 github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
 github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
 github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
+github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
+github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
 github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
 github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
 github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
 github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
 github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
+github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
 github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
 github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
 github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
 github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
+github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
 github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
+github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc=
+github.com/multiformats/go-multihash v0.2.1/go.mod h1:WxoMcYG85AZVQUyRyo9s4wULvW5qrI9vb2Lt6evduFc=
+github.com/multiformats/go-varint v0.0.6/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE=
 github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
+github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f h1:KUppIJq7/+SVif2QVs3tOP0zanoHgBEVAwHxUSIzRqU=
 github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
+github.com/mwitkow/grpc-proxy v0.0.0-20181017164139-0f1106ef9c76/go.mod h1:x5OoJHDHqxHS801UIuhqGl6QdSAEJvtausosHSdazIo=
+github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg=
+github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU=
+github.com/nats-io/nats-server/v2 v2.1.2/go.mod h1:Afk+wRZqkMQs/p45uXdrVLuab3gwv3Z8C4HTBu8GD/k=
+github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w=
+github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
+github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
+github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
 github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ=
 github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8=
 github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
+github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs=
+github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
+github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
+github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
+github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
+github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis=
+github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74=
+github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
+github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
+github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxSfWAKL3wpBW7V8scJMt8N8gnaMCS9E/cA=
+github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
+github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
+github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
+github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM=
 github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
 github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
+github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
 github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8=
 github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
 github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo=
 github.com/pelletier/go-toml/v2 v2.0.2 h1:+jQXlF3scKIcSEKkdHzXhCTDLPFi5r1wnK6yPS+49Gw=
 github.com/pelletier/go-toml/v2 v2.0.2/go.mod h1:MovirKjgVRESsAvNZlAjtFwV867yGuwRkXbG66OzopI=
+github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac=
+github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc=
+github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
 github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
 github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA=
+github.com/pkg/profile v1.6.0 h1:hUDfIISABYI59DyeB3OTay/HxSRwTQ8rB/H83k6r5dM=
+github.com/pkg/profile v1.6.0/go.mod h1:qBsxPvzyUincmltOk6iyRVxHYg4adc0OFOv72ZdLa18=
 github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg=
 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
 github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s=
 github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
+github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs=
 github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
+github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og=
 github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU=
 github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
 github.com/prometheus/client_golang v1.11.1/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
 github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
+github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
 github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
 github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
 github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
 github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
+github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA=
 github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4=
 github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
+github.com/prometheus/common v0.15.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s=
 github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc=
 github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
+github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
 github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
 github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
 github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
+github.com/prometheus/procfs v0.3.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
 github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
+github.com/rakyll/statik v0.1.6/go.mod h1:OEi9wJV/fMUAGx1eNjq75DKDsJVuEv1U0oYdX6GX8Zs=
+github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
+github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
 github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
 github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
 github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k=
 github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
+github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
+github.com/rs/cors v1.8.2 h1:KCooALfAYGs415Cwu5ABvv9n9509fSiG5SQJn/AQo4U=
+github.com/rs/cors v1.8.2/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU=
+github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
 github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
 github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
 github.com/sagikazarmark/crypt v0.6.0/go.mod h1:U8+INwJo3nBv1m6A/8OBXAq7Jnpspk5AxSgDyEQcea8=
+github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E=
 github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
+github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
 github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
 github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
 github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
+github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
 github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e h1:MRM5ITcdelLK2j1vwZ3Je0FKVCfqOLp5zO6trqMLYs0=
 github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e/go.mod h1:XV66xRDqSt+GTGFMVlhk3ULuV0y9ZmzeVGR4mloJI3M=
+github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
+github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
+github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
+github.com/soheilhy/cmux v0.1.5 h1:jjzc5WVemNEDTLwv9tlmemhC73tI08BNOIGwBOo10Js=
+github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0=
+github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY=
 github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
+github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
 github.com/spf13/afero v1.8.2/go.mod h1:CtAatgMJh6bJEIs48Ay/FOnkljP3WeGUG0MC1RfAqwo=
 github.com/spf13/afero v1.9.2 h1:j49Hj62F0n+DaZ1dDCvhABaPNSGNkt32oRFxI33IEMw=
 github.com/spf13/afero v1.9.2/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y=
 github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w=
 github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU=
+github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
 github.com/spf13/cobra v1.5.0 h1:X+jTBEBqF0bHN+9cSMgmfuvv2VHJ9ezmFNf9Y/XstYU=
 github.com/spf13/cobra v1.5.0/go.mod h1:dWXEIy2H428czQCjInthrTRUg7yKbok+2Qi/yBIJoUM=
 github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk=
 github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
+github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
 github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
 github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
 github.com/spf13/viper v1.12.0 h1:CZ7eSOd3kZoaYDLbXnmzgQI5RlciuXBMA+18HwHRfZQ=
 github.com/spf13/viper v1.12.0/go.mod h1:b6COn30jlNxbm/V2IqWiNWkJ+vZNiMNksliPCiuKtSI=
+github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
+github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
+github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI=
 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
 github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
 github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
 github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
@@ -394,11 +590,13 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5
 github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
-github.com/stretchr/testify v1.7.2 h1:4jaiDzPyXQvSd7D0EjG45355tLlV3VOECpq10pLC+8s=
 github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
+github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
+github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
 github.com/subosito/gotenv v1.3.0/go.mod h1:YzJjq/33h7nrwdY+iHMhEOEEbW0ovIz0tB6t6PwAXzs=
 github.com/subosito/gotenv v1.4.0 h1:yAzM1+SmVcz5R4tXGsNMu1jUl2aOJXoiWUCEwwnGrvs=
 github.com/subosito/gotenv v1.4.0/go.mod h1:mZd6rFysKEcUhUHXJk0C/08wAgyDBFuwEYL7vWWGaGo=
+github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
 github.com/ttacon/builder v0.0.0-20170518171403-c099f663e1c2 h1:5u+EJUQiosu3JFX0XS0qTf5FznsMOzTjGqavBGuCbo0=
 github.com/ttacon/builder v0.0.0-20170518171403-c099f663e1c2/go.mod h1:4kyMkleCiLkgY6z8gK5BkI01ChBtxR0ro3I1ZDcGM3w=
 github.com/ttacon/libphonenumber v1.2.1 h1:fzOfY5zUADkCkbIafAed11gL1sW+bJ26p6zWLBMElR4=
@@ -406,6 +604,13 @@ github.com/ttacon/libphonenumber v1.2.1/go.mod h1:E0TpmdVMq5dyVlQ7oenAkhsLu86OkU
 github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM=
 github.com/tyler-smith/go-bip39 v1.1.0 h1:5eUemwrMargf3BSLRRCalXT93Ns6pQJIjYQN2nyfOP8=
 github.com/tyler-smith/go-bip39 v1.1.0/go.mod h1:gUYDtqQw1JS3ZJ8UWVcGTGqqr6YIN3CWg+kkNaLt55U=
+github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo=
+github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
+github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs=
+github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
+github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
+github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
+github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
 github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
 github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
 github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
@@ -424,51 +629,61 @@ github.com/zeebo/pcg v1.0.1 h1:lyqfGeWiv4ahac6ttHs+I5hwtH/+1mrhlCtVNQM2kHo=
 github.com/zeebo/pcg v1.0.1/go.mod h1:09F0S9iiKrwn9rlI5yjLkmrug154/YRW6KnnXVDM/l4=
 gitlab.com/elixxir/bloomfilter v0.0.0-20211222005329-7d931ceead6f h1:yXGvNBqzZwAhDYlSnxPRbgor6JWoOt1Z7s3z1O9JR40=
 gitlab.com/elixxir/bloomfilter v0.0.0-20211222005329-7d931ceead6f/go.mod h1:H6jztdm0k+wEV2QGK/KYA+MY9nj9Zzatux/qIvDDv3k=
-gitlab.com/elixxir/comms v0.0.4-0.20220805121030-b95005ac4528 h1:1js4QzrDI5djjIVkj1mZiWkxh7K2h5/Od/X/lyftILA=
-gitlab.com/elixxir/comms v0.0.4-0.20220805121030-b95005ac4528/go.mod h1:Zi1O21+pKwSNNvQ7akyVRnppR79z+4CzJs6njIRaJCA=
+gitlab.com/elixxir/comms v0.0.4-0.20220913220502-eed192f654bd h1:2nHE7EoptSTBFjCxMeAveKT6urbguCwgg8Jx7XYEVe4=
+gitlab.com/elixxir/comms v0.0.4-0.20220913220502-eed192f654bd/go.mod h1:AO6XkMhaHJW8eXlgL5m3UUcJqsSP8F5Wm1GX+wyq/rw=
+gitlab.com/elixxir/comms v0.0.4-0.20220916185715-f1e9a5eda939 h1:+VRx2ULHKs040bBhDAOKNCZnbcXxUk3jD9JoKQzQpLk=
+gitlab.com/elixxir/comms v0.0.4-0.20220916185715-f1e9a5eda939/go.mod h1:AO6XkMhaHJW8eXlgL5m3UUcJqsSP8F5Wm1GX+wyq/rw=
+gitlab.com/elixxir/comms v0.0.4-0.20221005205938-10f2defa5b33 h1:mtn/b+/+cMoZNSEo6293U48uqz+aE0si90mPwlhh08w=
+gitlab.com/elixxir/comms v0.0.4-0.20221005205938-10f2defa5b33/go.mod h1:oRteMH+R5t1j/FZ+KJJnZUcqJO2sLXnWksN5HPkZUIo=
 gitlab.com/elixxir/crypto v0.0.0-20200804182833-984246dea2c4/go.mod h1:ucm9SFKJo+K0N2GwRRpaNr+tKXMIOVWzmyUD0SbOu2c=
 gitlab.com/elixxir/crypto v0.0.3/go.mod h1:ZNgBOblhYToR4m8tj4cMvJ9UsJAUKq+p0gCp07WQmhA=
-gitlab.com/elixxir/crypto v0.0.7-0.20220317172048-3de167bd9406/go.mod h1:tD6XjtQh87T2nKZL5I/pYPck5M2wLpkZ1Oz7H/LqO10=
-gitlab.com/elixxir/crypto v0.0.7-0.20220808171640-473891de4c46 h1:C8nAiMnL8IOGjQ5qErbpzAjRMVFMoB1GunYk8pGOEz8=
-gitlab.com/elixxir/crypto v0.0.7-0.20220808171640-473891de4c46/go.mod h1:Oy+VWQ2Sa0Ybata3oTV+Yc46hkaDwAsuIMW0wJ01z2M=
-gitlab.com/elixxir/ekv v0.1.7 h1:OW2z+N4QCqqMFzouAwFTWWMKz0Y/PDhyYReN7gQ5NiQ=
-gitlab.com/elixxir/ekv v0.1.7/go.mod h1:e6WPUt97taFZe5PFLPb1Dupk7tqmDCTQu1kkstqJvw4=
+gitlab.com/elixxir/crypto v0.0.7-0.20220913220142-ab0771bad0af/go.mod h1:QF8SzsrYh9Elip9EUYUDAhPjqO9DGrrrQxYHvn+VXok=
+gitlab.com/elixxir/crypto v0.0.7-0.20220920002307-5541473e9aa7 h1:9IsBtL8zcUG86XcfNUVIKcnlL5tyKlyQt1cJ5nogr1U=
+gitlab.com/elixxir/crypto v0.0.7-0.20220920002307-5541473e9aa7/go.mod h1:QF8SzsrYh9Elip9EUYUDAhPjqO9DGrrrQxYHvn+VXok=
+gitlab.com/elixxir/crypto v0.0.7-0.20220923135535-fb10d313632a h1:n12oIGF9GzfA/0ZTggCjubTxOZPF8p9WINfkdko9e7E=
+gitlab.com/elixxir/crypto v0.0.7-0.20220923135535-fb10d313632a/go.mod h1:QF8SzsrYh9Elip9EUYUDAhPjqO9DGrrrQxYHvn+VXok=
+gitlab.com/elixxir/crypto v0.0.7-0.20220923164228-3f5620181081 h1:xrTNr42Id8rvq6zH+pkoxxCrLhFMpkMC3f34y5mUfQE=
+gitlab.com/elixxir/crypto v0.0.7-0.20220923164228-3f5620181081/go.mod h1:QF8SzsrYh9Elip9EUYUDAhPjqO9DGrrrQxYHvn+VXok=
+gitlab.com/elixxir/crypto v0.0.7-0.20220923233816-0364f1b203c6 h1:ZCMqzKB86nrs9ldIoF2ZHvcExrkXIIIeH2RlNVwZx2A=
+gitlab.com/elixxir/crypto v0.0.7-0.20220923233816-0364f1b203c6/go.mod h1:QF8SzsrYh9Elip9EUYUDAhPjqO9DGrrrQxYHvn+VXok=
+gitlab.com/elixxir/crypto v0.0.7-0.20221003185354-b091598d2322 h1:8unQE70BDNRXTWUbjOO9d4kWyh19LySlTZo0Jqx0gPE=
+gitlab.com/elixxir/crypto v0.0.7-0.20221003185354-b091598d2322/go.mod h1:QF8SzsrYh9Elip9EUYUDAhPjqO9DGrrrQxYHvn+VXok=
+gitlab.com/elixxir/ekv v0.2.1 h1:dtwbt6KmAXG2Tik5d60iDz2fLhoFBgWwST03p7T+9Is=
+gitlab.com/elixxir/ekv v0.2.1/go.mod h1:USLD7xeDnuZEavygdrgzNEwZXeLQJK/w1a+htpN+JEU=
 gitlab.com/elixxir/primitives v0.0.0-20200731184040-494269b53b4d/go.mod h1:OQgUZq7SjnE0b+8+iIAT2eqQF+2IFHn73tOo+aV11mg=
 gitlab.com/elixxir/primitives v0.0.0-20200804170709-a1896d262cd9/go.mod h1:p0VelQda72OzoUckr1O+vPW0AiFe0nyKQ6gYcmFSuF8=
 gitlab.com/elixxir/primitives v0.0.0-20200804182913-788f47bded40/go.mod h1:tzdFFvb1ESmuTCOl1z6+yf6oAICDxH2NPUemVgoNLxc=
 gitlab.com/elixxir/primitives v0.0.1/go.mod h1:kNp47yPqja2lHSiS4DddTvFpB/4D9dB2YKnw5c+LJCE=
-gitlab.com/elixxir/primitives v0.0.3-0.20220222212109-d412a6e46623/go.mod h1:MtFIyJUQn9P7djzVlBpEYkPNnnWFTjZvw89swoXY+QM=
-gitlab.com/elixxir/primitives v0.0.3-0.20220323183834-b98f255361b8/go.mod h1:MtFIyJUQn9P7djzVlBpEYkPNnnWFTjZvw89swoXY+QM=
-gitlab.com/elixxir/primitives v0.0.3-0.20220606195757-40f7a589347f h1:CTf2+ewHWYrzp5Ar3RwNvHePfTHyFniJTVjFW4zqoaE=
 gitlab.com/elixxir/primitives v0.0.3-0.20220606195757-40f7a589347f/go.mod h1:9Bb2+u+CDSwsEU5Droo6saDAXuBDvLRjexpBhPAYxhA=
+gitlab.com/elixxir/primitives v0.0.3-0.20220810173935-592f34a88326/go.mod h1:9Bb2+u+CDSwsEU5Droo6saDAXuBDvLRjexpBhPAYxhA=
+gitlab.com/elixxir/primitives v0.0.3-0.20220901220638-1acc75fabdc6 h1:/cxxZBP5jTPDpC3zgOx9vV1ojmJyG8pYtkl3IbcewNQ=
+gitlab.com/elixxir/primitives v0.0.3-0.20220901220638-1acc75fabdc6/go.mod h1:9Bb2+u+CDSwsEU5Droo6saDAXuBDvLRjexpBhPAYxhA=
 gitlab.com/xx_network/comms v0.0.0-20200805174823-841427dd5023/go.mod h1:owEcxTRl7gsoM8c3RQ5KAm5GstxrJp5tn+6JfQ4z5Hw=
-gitlab.com/xx_network/comms v0.0.4-0.20220315161313-76acb14429ac/go.mod h1:isHnwem0v4rTcwwHP455FhVlFyPcHkHiVz+N3s/uCSI=
-gitlab.com/xx_network/comms v0.0.4-0.20220630163702-f3d372ef6acd h1:qYR2V/8KliGyJ2clWpVYhpgwpnfS1MXGpAbrFoOkSWk=
-gitlab.com/xx_network/comms v0.0.4-0.20220630163702-f3d372ef6acd/go.mod h1:TraR4sW+YxK/2CV+IQUNaAV61+ElrBV0kXd5HLEjM7M=
+gitlab.com/xx_network/comms v0.0.4-0.20220913215811-c4bf83b27de3 h1:7mReTvEUVoI5Qpltcmbodc/j6rdPPHDIvenY4ZmWP7o=
+gitlab.com/xx_network/comms v0.0.4-0.20220913215811-c4bf83b27de3/go.mod h1:E2QKOKyPKLRjLUwMxgZpTKueEsHDEqshfqOHJ54ttxU=
+gitlab.com/xx_network/comms v0.0.4-0.20220916185248-8a984b8594de h1:44VKuVgT6X1l+MX8/oNmYORA+pa4nkOWV8hYxi4SCzc=
+gitlab.com/xx_network/comms v0.0.4-0.20220916185248-8a984b8594de/go.mod h1:E2QKOKyPKLRjLUwMxgZpTKueEsHDEqshfqOHJ54ttxU=
+gitlab.com/xx_network/comms v0.0.4-0.20221005205845-b34d538ffd85/go.mod h1:E2QKOKyPKLRjLUwMxgZpTKueEsHDEqshfqOHJ54ttxU=
 gitlab.com/xx_network/crypto v0.0.3/go.mod h1:DF2HYvvCw9wkBybXcXAgQMzX+MiGbFPjwt3t17VRqRE=
 gitlab.com/xx_network/crypto v0.0.4/go.mod h1:+lcQEy+Th4eswFgQDwT0EXKp4AXrlubxalwQFH5O0Mk=
-gitlab.com/xx_network/crypto v0.0.5-0.20220222212031-750f7e8a01f4/go.mod h1:6apvsoHCQJDjO0J4E3uhR3yO9tTz/Mq5be5rjB3tQPU=
-gitlab.com/xx_network/crypto v0.0.5-0.20220317171841-084640957d71/go.mod h1:/SJf+R75E+QepdTLh0H1/udsovxx2Q5ru34q1v0umKk=
-gitlab.com/xx_network/crypto v0.0.5-0.20220606200528-3f886fe49e81/go.mod h1:/SJf+R75E+QepdTLh0H1/udsovxx2Q5ru34q1v0umKk=
-gitlab.com/xx_network/crypto v0.0.5-0.20220729193517-1e5e96f39f6e h1:k+M0zo9eyL2mGaduggdQnwxzOIqOIBV9WIt1QCq92sA=
-gitlab.com/xx_network/crypto v0.0.5-0.20220729193517-1e5e96f39f6e/go.mod h1:/SJf+R75E+QepdTLh0H1/udsovxx2Q5ru34q1v0umKk=
+gitlab.com/xx_network/crypto v0.0.5-0.20220913213008-98764f5b3287 h1:Jd71F8f/8rieWybMqkxpKKZVVyGkeCNZWZcviGGnQ9A=
+gitlab.com/xx_network/crypto v0.0.5-0.20220913213008-98764f5b3287/go.mod h1:/SJf+R75E+QepdTLh0H1/udsovxx2Q5ru34q1v0umKk=
 gitlab.com/xx_network/primitives v0.0.0-20200803231956-9b192c57ea7c/go.mod h1:wtdCMr7DPePz9qwctNoAUzZtbOSHSedcK++3Df3psjA=
 gitlab.com/xx_network/primitives v0.0.0-20200804183002-f99f7a7284da/go.mod h1:OK9xevzWCaPO7b1wiluVJGk7R5ZsuC7pHY5hteZFQug=
 gitlab.com/xx_network/primitives v0.0.2/go.mod h1:cs0QlFpdMDI6lAo61lDRH2JZz+3aVkHy+QogOB6F/qc=
 gitlab.com/xx_network/primitives v0.0.4-0.20220222211843-901fa4a2d72b/go.mod h1:9imZHvYwNFobxueSvVtHneZLk9wTK7HQTzxPm+zhFhE=
-gitlab.com/xx_network/primitives v0.0.4-0.20220317172007-4d2a53e6e669/go.mod h1:AXVVFt7dDAeIUpOGPiStCcUIKsBXLWbmV/BgZ4T+tOo=
-gitlab.com/xx_network/primitives v0.0.4-0.20220324193139-b292d1ae6e7e/go.mod h1:AXVVFt7dDAeIUpOGPiStCcUIKsBXLWbmV/BgZ4T+tOo=
-gitlab.com/xx_network/primitives v0.0.4-0.20220630163313-7890038258c6/go.mod h1:AXVVFt7dDAeIUpOGPiStCcUIKsBXLWbmV/BgZ4T+tOo=
-gitlab.com/xx_network/primitives v0.0.4-0.20220712193914-aebd8544396e h1:zRRo/v3KUo3MtpjNJaB03LR+Zi2g1afYF8yKWl1t19o=
-gitlab.com/xx_network/primitives v0.0.4-0.20220712193914-aebd8544396e/go.mod h1:AXVVFt7dDAeIUpOGPiStCcUIKsBXLWbmV/BgZ4T+tOo=
-gitlab.com/xx_network/primitives v0.0.4-0.20221010192422-3479f09b7769 h1:BBYSog3VSKudey4rhWnCw54PcGcD4YRjTrnwzOhJ/GE=
-gitlab.com/xx_network/primitives v0.0.4-0.20221010192422-3479f09b7769/go.mod h1:AXVVFt7dDAeIUpOGPiStCcUIKsBXLWbmV/BgZ4T+tOo=
+gitlab.com/xx_network/primitives v0.0.4-0.20220809193445-9fc0a5209548 h1:6orM1nSt9H/uN/oqbF8RYmwZ/OuWU6h79Fp+tWeHIPY=
+gitlab.com/xx_network/primitives v0.0.4-0.20220809193445-9fc0a5209548/go.mod h1:AXVVFt7dDAeIUpOGPiStCcUIKsBXLWbmV/BgZ4T+tOo=
 gitlab.com/xx_network/ring v0.0.3-0.20220222211904-da613960ad93 h1:eJZrXqHsMmmejEPWw8gNAt0I8CGAMNO/7C339Zco3TM=
 gitlab.com/xx_network/ring v0.0.3-0.20220222211904-da613960ad93/go.mod h1:aLzpP2TiZTQut/PVHR40EJAomzugDdHXetbieRClXIM=
+go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
+go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg=
 go.etcd.io/etcd/api/v3 v3.5.4/go.mod h1:5GB2vv4A4AOn3yk7MftYGHkUfGtDHnEraIjym4dYz5A=
 go.etcd.io/etcd/client/pkg/v3 v3.5.4/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g=
 go.etcd.io/etcd/client/v2 v2.305.4/go.mod h1:Ud+VUwIi9/uQHOMA+4ekToJ12lTxlv0zB/+DHwTGEbU=
 go.etcd.io/etcd/client/v3 v3.5.4/go.mod h1:ZaRkVgBZC+L+dLCjTcF1hRXpgZXQPOvnA/Ak/gq3kiY=
+go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
+go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
 go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
 go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
 go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
@@ -477,30 +692,44 @@ go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
 go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
 go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
 go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
-go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
+go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
+go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
+go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
+go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
 go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
+go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ=
+go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
+go.uber.org/goleak v0.10.0/go.mod h1:VCZuO8V8mFPlL0F5J5GK1rtHV3DrFcQ1R8ryq7FK0aI=
+go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
+go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
+go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
 go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
 go.uber.org/ratelimit v0.2.0 h1:UQE2Bgi7p2B85uP5dC2bbRtig0C+OeNRnNEafLjsLPA=
 go.uber.org/ratelimit v0.2.0/go.mod h1:YYBV4e4naJvhpitQrWJu1vCpgB7CboMe0qhltKt6mUg=
+go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
+go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
+go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
 go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=
 golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
 golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY=
 golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
 golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
 golang.org/x/crypto v0.0.0-20200707235045-ab33eee955e0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
 golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
-golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
 golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
 golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
 golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
 golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
-golang.org/x/crypto v0.0.0-20220128200615-198e4374d7ed/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
 golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
 golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
+golang.org/x/crypto v0.0.0-20220518034528-6f7dac969898/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
+golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
 golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa h1:zuSxTR4o9y82ebqCUJYNGJbGPo6sKVl54f/TVDObg1c=
 golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
 golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
@@ -513,6 +742,7 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0
 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
 golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
 golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
+golang.org/x/exp v0.0.0-20200331195152-e8c3332aa8e5/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw=
 golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
 golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
 golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
@@ -540,8 +770,13 @@ golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
 golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
@@ -552,6 +787,7 @@ golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLL
 golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
@@ -560,6 +796,7 @@ golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLL
 golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200421231249-e086a090c8fd/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
 golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
 golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
 golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
@@ -570,6 +807,7 @@ golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81R
 golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
 golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
 golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
+golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
 golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
 golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
 golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
@@ -578,7 +816,7 @@ golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLd
 golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
 golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8=
 golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
-golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
 golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
 golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
 golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
@@ -586,8 +824,8 @@ golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su
 golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
 golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
 golang.org/x/net v0.0.0-20220520000938-2e3eb7b945c2/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
-golang.org/x/net v0.0.0-20220802222814-0bcc04d9c69b h1:3ogNYyK4oIQdIKzTu68hQrr4iuVxF3AxKl9Aj/eDrw0=
-golang.org/x/net v0.0.0-20220802222814-0bcc04d9c69b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
+golang.org/x/net v0.0.0-20220822230855-b0a4917ee28c h1:JVAXQ10yGGVbSyoer5VILysz6YKjdNT2bsvlayjqhes=
+golang.org/x/net v0.0.0-20220822230855-b0a4917ee28c/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
 golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
 golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
 golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -623,7 +861,11 @@ golang.org/x/sync v0.0.0-20220513210516-0976fa681c29/go.mod h1:RxMgew5VJxzue5/jJ
 golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -634,6 +876,7 @@ golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7w
 golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -641,6 +884,7 @@ golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7w
 golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -653,6 +897,7 @@ golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7w
 golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -662,7 +907,6 @@ golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7w
 golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200917073148-efd3b9a0ff20/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20201014080544-cc95f250f6bc/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -689,6 +933,7 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc
 golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@@ -721,15 +966,19 @@ golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
 golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
+golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
 golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
 golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
 golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
 golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
 golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
 golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
@@ -740,6 +989,9 @@ golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtn
 golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
@@ -747,6 +999,7 @@ golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtn
 golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
 golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
 golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
 golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
 golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
@@ -785,6 +1038,7 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T
 golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=
+google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=
 google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
 google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
 google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
@@ -825,6 +1079,7 @@ google.golang.org/api v0.75.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69
 google.golang.org/api v0.78.0/go.mod h1:1Sg78yoMLOhlQTeF+ARBoytAcH1NNyyl390YMy6rKmw=
 google.golang.org/api v0.81.0/go.mod h1:FA6Mb/bZxj706H2j+j2d6mHEEaHBmbbWnkfvmorOCko=
 google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
+google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
 google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
 google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
 google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
@@ -836,6 +1091,7 @@ google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRn
 google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
 google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
 google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s=
 google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
 google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
 google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
@@ -846,12 +1102,14 @@ google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvx
 google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
 google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
 google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=
+google.golang.org/genproto v0.0.0-20200204235621-fb4a7afc5178/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=
 google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
 google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
 google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
 google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
 google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
 google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
 google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
 google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
 google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
@@ -867,6 +1125,7 @@ google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6D
 google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
 google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
 google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20210126160654-44e461bb6506/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
 google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
 google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
 google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
@@ -909,12 +1168,17 @@ google.golang.org/genproto v0.0.0-20220421151946-72621c1f0bd3/go.mod h1:8w6bsBMX
 google.golang.org/genproto v0.0.0-20220429170224-98d788798c3e/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=
 google.golang.org/genproto v0.0.0-20220505152158-f39f71e6c8f3/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4=
 google.golang.org/genproto v0.0.0-20220519153652-3a47de7e79bd/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4=
-google.golang.org/genproto v0.0.0-20220802133213-ce4fa296bf78 h1:QntLWYqZeuBtJkth3m/6DLznnI0AHJr+AgJXvVh/izw=
-google.golang.org/genproto v0.0.0-20220802133213-ce4fa296bf78/go.mod h1:iHe1svFLAZg9VWz891+QbRMwUv9O/1Ww+/mngYeThbc=
+google.golang.org/genproto v0.0.0-20220822174746-9e6da59bd2fc h1:Nf+EdcTLHR8qDNN/KfkQL0u0ssxt9OhbaWCl5C0ucEI=
+google.golang.org/genproto v0.0.0-20220822174746-9e6da59bd2fc/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk=
+google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
 google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
+google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM=
 google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
+google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
 google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
+google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
 google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
+google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
 google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
 google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
 google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
@@ -924,6 +1188,7 @@ google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3Iji
 google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
 google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
 google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
+google.golang.org/grpc v1.32.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
 google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
 google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
 google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8=
@@ -941,8 +1206,9 @@ google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ5
 google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ=
 google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
 google.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
-google.golang.org/grpc v1.48.0 h1:rQOsyJ/8+ufEDJd/Gdsz7HG220Mh9HAhFHRGnIjda0w=
 google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
+google.golang.org/grpc v1.49.0 h1:WTLtQzmQori5FUH25Pq4WT22oCsv8USpQ+F6rqtsmxw=
+google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI=
 google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw=
 google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
 google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
@@ -967,10 +1233,17 @@ gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8
 gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
+gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
 gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
+gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
+gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o=
 gopkg.in/ini.v1 v1.66.4/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
 gopkg.in/ini.v1 v1.66.6 h1:LATuAqN/shcYAOkv3wl2L4rkaKqkcgTBQjOyYDvcPKI=
 gopkg.in/ini.v1 v1.66.6/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
+gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
+gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
+gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
+gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
 gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
@@ -986,6 +1259,7 @@ gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C
 gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
 gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
 honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
 honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
 honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
@@ -993,7 +1267,13 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh
 honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
 honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
 honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
+lukechampine.com/blake3 v1.1.6/go.mod h1:tkKEOtDkNtklkXtLNEOGNq5tcV90tJiA1vAA12R78LA=
+nhooyr.io/websocket v1.8.6/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0=
+nhooyr.io/websocket v1.8.7 h1:usjR2uOr/zjjkVMy0lW+PPohFok7PCow5sDjLgX4P4g=
+nhooyr.io/websocket v1.8.7/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0=
 rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
 rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
 rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
+sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
 sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=
+sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU=
diff --git a/groupChat/compileProtobuf.sh b/groupChat/compileProtobuf.sh
new file mode 100644
index 0000000000000000000000000000000000000000..f8039748c3b3add0a501215214ee9ea6e53c75a9
--- /dev/null
+++ b/groupChat/compileProtobuf.sh
@@ -0,0 +1,14 @@
+#!/bin/bash
+################################################################################
+## Copyright © 2022 xx foundation                                             ##
+##                                                                            ##
+## Use of this source code is governed by a license that can be found in the  ##
+## LICENSE file.                                                              ##
+################################################################################
+
+# This script will compile the Protobuf file to a Go file (pb.go).
+# This is meant to be called from the top level of the repo.
+
+cd ./groupChat/ || return
+
+protoc --go_out=. --go_opt=paths=source_relative ./gcMessages.proto
diff --git a/groupChat/e2eManager_test.go b/groupChat/e2eManager_test.go
index 37e4019cb8442cf95c8537cbb412d2d4a5d1e585..2d89504277be61b03a78908a61a7391d5f61efa5 100644
--- a/groupChat/e2eManager_test.go
+++ b/groupChat/e2eManager_test.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package groupChat
 
 import (
@@ -11,7 +18,7 @@ import (
 	"gitlab.com/elixxir/client/e2e/receive"
 	"gitlab.com/elixxir/client/stoppable"
 	"gitlab.com/elixxir/crypto/cyclic"
-	"gitlab.com/elixxir/crypto/e2e"
+	cryptoE2e "gitlab.com/elixxir/crypto/e2e"
 	"gitlab.com/xx_network/primitives/id"
 	"sync"
 	"testing"
@@ -65,16 +72,15 @@ func (tnm *testE2eManager) GetE2eMsg(i int) testE2eMessage {
 }
 
 func (tnm *testE2eManager) SendE2E(_ catalog.MessageType, recipient *id.ID,
-	payload []byte, _ clientE2E.Params) ([]id.Round, e2e.MessageID, time.Time,
-	error) {
+	payload []byte, _ clientE2E.Params) (cryptoE2e.SendReport, error) {
 	tnm.Lock()
 	defer tnm.Unlock()
 
 	tnm.errSkip++
 	if tnm.sendErr == 1 {
-		return nil, e2e.MessageID{}, time.Time{}, errors.New("SendE2E error")
+		return cryptoE2e.SendReport{}, errors.New("SendE2E error")
 	} else if tnm.sendErr == 2 && tnm.errSkip%2 == 0 {
-		return nil, e2e.MessageID{}, time.Time{}, errors.New("SendE2E error")
+		return cryptoE2e.SendReport{}, errors.New("SendE2E error")
 	}
 
 	tnm.e2eMessages = append(tnm.e2eMessages, testE2eMessage{
@@ -82,7 +88,7 @@ func (tnm *testE2eManager) SendE2E(_ catalog.MessageType, recipient *id.ID,
 		Payload:   payload,
 	})
 
-	return []id.Round{0, 1, 2, 3}, e2e.MessageID{}, time.Time{}, nil
+	return cryptoE2e.SendReport{RoundList: []id.Round{0, 1, 2, 3}}, nil
 }
 
 func (*testE2eManager) RegisterListener(*id.ID, catalog.MessageType, receive.Listener) receive.ListenerID {
diff --git a/groupChat/gcMessages.pb.go b/groupChat/gcMessages.pb.go
index d31c3001125f286af67fb1eacf6986b193513e7c..17cdd83d6f1ab07b2f0b44ed1a33ee017ccb63ed 100644
--- a/groupChat/gcMessages.pb.go
+++ b/groupChat/gcMessages.pb.go
@@ -1,15 +1,15 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 // Code generated by protoc-gen-go. DO NOT EDIT.
 // versions:
-// 	protoc-gen-go v1.26.0
-// 	protoc        v3.17.3
-// source: groupChat/gcMessages.proto
+// 	protoc-gen-go v1.27.1
+// 	protoc        v3.15.6
+// source: gcMessages.proto
 
 package groupChat
 
@@ -44,7 +44,7 @@ type Request struct {
 func (x *Request) Reset() {
 	*x = Request{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_groupChat_gcMessages_proto_msgTypes[0]
+		mi := &file_gcMessages_proto_msgTypes[0]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -57,7 +57,7 @@ func (x *Request) String() string {
 func (*Request) ProtoMessage() {}
 
 func (x *Request) ProtoReflect() protoreflect.Message {
-	mi := &file_groupChat_gcMessages_proto_msgTypes[0]
+	mi := &file_gcMessages_proto_msgTypes[0]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -70,7 +70,7 @@ func (x *Request) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use Request.ProtoReflect.Descriptor instead.
 func (*Request) Descriptor() ([]byte, []int) {
-	return file_groupChat_gcMessages_proto_rawDescGZIP(), []int{0}
+	return file_gcMessages_proto_rawDescGZIP(), []int{0}
 }
 
 func (x *Request) GetName() []byte {
@@ -115,45 +115,44 @@ func (x *Request) GetCreated() int64 {
 	return 0
 }
 
-var File_groupChat_gcMessages_proto protoreflect.FileDescriptor
-
-var file_groupChat_gcMessages_proto_rawDesc = []byte{
-	0x0a, 0x1a, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x43, 0x68, 0x61, 0x74, 0x2f, 0x67, 0x63, 0x4d, 0x65,
-	0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x11, 0x67, 0x63,
-	0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x22,
-	0xad, 0x01, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e,
-	0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12,
-	0x1e, 0x0a, 0x0a, 0x69, 0x64, 0x50, 0x72, 0x65, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20,
-	0x01, 0x28, 0x0c, 0x52, 0x0a, 0x69, 0x64, 0x50, 0x72, 0x65, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x12,
-	0x20, 0x0a, 0x0b, 0x6b, 0x65, 0x79, 0x50, 0x72, 0x65, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x18, 0x03,
-	0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x6b, 0x65, 0x79, 0x50, 0x72, 0x65, 0x69, 0x6d, 0x61, 0x67,
-	0x65, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x18, 0x04, 0x20, 0x01,
-	0x28, 0x0c, 0x52, 0x07, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x6d,
-	0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x6d, 0x65,
-	0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64,
-	0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x42,
-	0x25, 0x5a, 0x23, 0x67, 0x69, 0x74, 0x6c, 0x61, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x65, 0x6c,
-	0x69, 0x78, 0x78, 0x69, 0x72, 0x2f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x2f, 0x67, 0x72, 0x6f,
-	0x75, 0x70, 0x43, 0x68, 0x61, 0x74, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+var File_gcMessages_proto protoreflect.FileDescriptor
+
+var file_gcMessages_proto_rawDesc = []byte{
+	0x0a, 0x10, 0x67, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f,
+	0x74, 0x6f, 0x12, 0x09, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x43, 0x68, 0x61, 0x74, 0x22, 0xad, 0x01,
+	0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d,
+	0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1e, 0x0a,
+	0x0a, 0x69, 0x64, 0x50, 0x72, 0x65, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28,
+	0x0c, 0x52, 0x0a, 0x69, 0x64, 0x50, 0x72, 0x65, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x12, 0x20, 0x0a,
+	0x0b, 0x6b, 0x65, 0x79, 0x50, 0x72, 0x65, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x18, 0x03, 0x20, 0x01,
+	0x28, 0x0c, 0x52, 0x0b, 0x6b, 0x65, 0x79, 0x50, 0x72, 0x65, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x12,
+	0x18, 0x0a, 0x07, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c,
+	0x52, 0x07, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73,
+	0x73, 0x61, 0x67, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73,
+	0x61, 0x67, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x18, 0x06,
+	0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x42, 0x25, 0x5a,
+	0x23, 0x67, 0x69, 0x74, 0x6c, 0x61, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x65, 0x6c, 0x69, 0x78,
+	0x78, 0x69, 0x72, 0x2f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x2f, 0x67, 0x72, 0x6f, 0x75, 0x70,
+	0x43, 0x68, 0x61, 0x74, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
 }
 
 var (
-	file_groupChat_gcMessages_proto_rawDescOnce sync.Once
-	file_groupChat_gcMessages_proto_rawDescData = file_groupChat_gcMessages_proto_rawDesc
+	file_gcMessages_proto_rawDescOnce sync.Once
+	file_gcMessages_proto_rawDescData = file_gcMessages_proto_rawDesc
 )
 
-func file_groupChat_gcMessages_proto_rawDescGZIP() []byte {
-	file_groupChat_gcMessages_proto_rawDescOnce.Do(func() {
-		file_groupChat_gcMessages_proto_rawDescData = protoimpl.X.CompressGZIP(file_groupChat_gcMessages_proto_rawDescData)
+func file_gcMessages_proto_rawDescGZIP() []byte {
+	file_gcMessages_proto_rawDescOnce.Do(func() {
+		file_gcMessages_proto_rawDescData = protoimpl.X.CompressGZIP(file_gcMessages_proto_rawDescData)
 	})
-	return file_groupChat_gcMessages_proto_rawDescData
+	return file_gcMessages_proto_rawDescData
 }
 
-var file_groupChat_gcMessages_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
-var file_groupChat_gcMessages_proto_goTypes = []interface{}{
-	(*Request)(nil), // 0: gcRequestMessages.Request
+var file_gcMessages_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
+var file_gcMessages_proto_goTypes = []interface{}{
+	(*Request)(nil), // 0: groupChat.Request
 }
-var file_groupChat_gcMessages_proto_depIdxs = []int32{
+var file_gcMessages_proto_depIdxs = []int32{
 	0, // [0:0] is the sub-list for method output_type
 	0, // [0:0] is the sub-list for method input_type
 	0, // [0:0] is the sub-list for extension type_name
@@ -161,13 +160,13 @@ var file_groupChat_gcMessages_proto_depIdxs = []int32{
 	0, // [0:0] is the sub-list for field type_name
 }
 
-func init() { file_groupChat_gcMessages_proto_init() }
-func file_groupChat_gcMessages_proto_init() {
-	if File_groupChat_gcMessages_proto != nil {
+func init() { file_gcMessages_proto_init() }
+func file_gcMessages_proto_init() {
+	if File_gcMessages_proto != nil {
 		return
 	}
 	if !protoimpl.UnsafeEnabled {
-		file_groupChat_gcMessages_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
+		file_gcMessages_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
 			switch v := v.(*Request); i {
 			case 0:
 				return &v.state
@@ -184,18 +183,18 @@ func file_groupChat_gcMessages_proto_init() {
 	out := protoimpl.TypeBuilder{
 		File: protoimpl.DescBuilder{
 			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
-			RawDescriptor: file_groupChat_gcMessages_proto_rawDesc,
+			RawDescriptor: file_gcMessages_proto_rawDesc,
 			NumEnums:      0,
 			NumMessages:   1,
 			NumExtensions: 0,
 			NumServices:   0,
 		},
-		GoTypes:           file_groupChat_gcMessages_proto_goTypes,
-		DependencyIndexes: file_groupChat_gcMessages_proto_depIdxs,
-		MessageInfos:      file_groupChat_gcMessages_proto_msgTypes,
+		GoTypes:           file_gcMessages_proto_goTypes,
+		DependencyIndexes: file_gcMessages_proto_depIdxs,
+		MessageInfos:      file_gcMessages_proto_msgTypes,
 	}.Build()
-	File_groupChat_gcMessages_proto = out.File
-	file_groupChat_gcMessages_proto_rawDesc = nil
-	file_groupChat_gcMessages_proto_goTypes = nil
-	file_groupChat_gcMessages_proto_depIdxs = nil
+	File_gcMessages_proto = out.File
+	file_gcMessages_proto_rawDesc = nil
+	file_gcMessages_proto_goTypes = nil
+	file_gcMessages_proto_depIdxs = nil
 }
diff --git a/groupChat/gcMessages.proto b/groupChat/gcMessages.proto
index cc417505c71d9158a7e5e82fcc71ad25c8e3170f..46299a91d34c568f9d1590cbf87faae430f97ae3 100644
--- a/groupChat/gcMessages.proto
+++ b/groupChat/gcMessages.proto
@@ -1,14 +1,15 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 syntax = "proto3";
-package gcRequestMessages;
-option go_package = "gitlab.com/elixxir/client/groupChat";
 
+package groupChat;
+
+option go_package = "gitlab.com/elixxir/client/groupChat";
 
 // Request to join the group sent from leader to all members.
 message Request {
diff --git a/groupChat/generateProto.sh b/groupChat/generateProto.sh
deleted file mode 100644
index 43968a4aa112270ffb38ea9a2c5da91e309871f1..0000000000000000000000000000000000000000
--- a/groupChat/generateProto.sh
+++ /dev/null
@@ -1,3 +0,0 @@
-#!/bin/bash
-
-protoc --go_out=paths=source_relative:. groupChat/gcMessages.proto
diff --git a/groupChat/groupStore/dhKeyList.go b/groupChat/groupStore/dhKeyList.go
index 5319cd33eb964f8e4027f0a13357f6ae806d0c84..a00aa39b122aa82dbe9667891c318f2898c2652b 100644
--- a/groupChat/groupStore/dhKeyList.go
+++ b/groupChat/groupStore/dhKeyList.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package groupStore
 
diff --git a/groupChat/groupStore/dhKeyList_test.go b/groupChat/groupStore/dhKeyList_test.go
index e6b7a9e6965703d5ae3b7c9a5272597a173ac355..e7f37cc7c544cc52c7aeb92997154f44bb265681 100644
--- a/groupChat/groupStore/dhKeyList_test.go
+++ b/groupChat/groupStore/dhKeyList_test.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package groupStore
 
 import (
diff --git a/groupChat/groupStore/group.go b/groupChat/groupStore/group.go
index 2c7d3e91739af0494f74316fac517b937cd86e86..6a9ac4192f4939a8dcbf0c7d54b7c8c6dedb9b9d 100644
--- a/groupChat/groupStore/group.go
+++ b/groupChat/groupStore/group.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package groupStore
 
@@ -105,7 +105,7 @@ func (g Group) store(kv *versioned.KV) error {
 		Data:      g.Serialize(),
 	}
 
-	return kv.Set(groupStoreKey(g.ID), groupStoreVersion, obj)
+	return kv.Set(groupStoreKey(g.ID), obj)
 }
 
 // loadGroup returns the group with the corresponding ID from storage.
diff --git a/groupChat/groupStore/group_test.go b/groupChat/groupStore/group_test.go
index 047df74bc3981ef0b3f7b107c5c57fe87dac3ed6..a45be564da007da3164f2f3dc4e6853b3bcce773 100644
--- a/groupChat/groupStore/group_test.go
+++ b/groupChat/groupStore/group_test.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package groupStore
 
diff --git a/groupChat/groupStore/store.go b/groupChat/groupStore/store.go
index f2372be86f92e454dcd06320658d4beb11d69e4e..74140e19f91c1711f05b0f5c7f91abcee6ee0631 100644
--- a/groupChat/groupStore/store.go
+++ b/groupChat/groupStore/store.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package groupStore
 
@@ -126,7 +126,7 @@ func (s *Store) saveGroupList() error {
 	}
 
 	// Save to storage
-	return s.kv.Set(groupListStorageKey, groupListVersion, obj)
+	return s.kv.Set(groupListStorageKey, obj)
 }
 
 // serializeGroupIdList serializes the list of group IDs.
diff --git a/groupChat/groupStore/store_test.go b/groupChat/groupStore/store_test.go
index e5549f06b1afadeceb44dd3a8bb3d2ac3c0ce7d1..aaeaebe7eff15e4d51c566359d50ff22ae31b99c 100644
--- a/groupChat/groupStore/store_test.go
+++ b/groupChat/groupStore/store_test.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package groupStore
 
diff --git a/groupChat/groupStore/utils_test.go b/groupChat/groupStore/utils_test.go
index 8aff7c8400183aa61b352d1e4f44f4056f591de5..0ffefb6bf8538e76ee09994d568e106460c4f2d1 100644
--- a/groupChat/groupStore/utils_test.go
+++ b/groupChat/groupStore/utils_test.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package groupStore
 
diff --git a/groupChat/interface.go b/groupChat/interface.go
index 0355c90943797cb7ab98d7e02e648ba946f1692b..e9b14c911abe56c1072e571d552dca6047d35cbd 100644
--- a/groupChat/interface.go
+++ b/groupChat/interface.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 // Group chat is used to communicate the same content with multiple clients over
 // cMix. A group chat is controlled by a group leader who creates the group,
@@ -24,6 +24,7 @@ import (
 	"gitlab.com/elixxir/client/catalog"
 	"gitlab.com/elixxir/client/cmix"
 	"gitlab.com/elixxir/client/cmix/message"
+	"gitlab.com/elixxir/client/cmix/rounds"
 	"gitlab.com/elixxir/client/e2e"
 	"gitlab.com/elixxir/client/e2e/ratchet/partner"
 	sessionImport "gitlab.com/elixxir/client/e2e/ratchet/partner/session"
@@ -32,7 +33,7 @@ import (
 	"gitlab.com/elixxir/client/storage"
 	"gitlab.com/elixxir/client/xxdk"
 	"gitlab.com/elixxir/crypto/cyclic"
-	crypto "gitlab.com/elixxir/crypto/e2e"
+	cryptoE2e "gitlab.com/elixxir/crypto/e2e"
 	"gitlab.com/elixxir/crypto/fastRNG"
 	"gitlab.com/elixxir/crypto/group"
 	"gitlab.com/xx_network/primitives/id"
@@ -68,7 +69,7 @@ type GroupChat interface {
 	// The send fails if the message is too long. Returns the ID of the round
 	// sent on and the timestamp of the message send.
 	Send(groupID *id.ID, tag string, message []byte) (
-		id.Round, time.Time, group.MessageID, error)
+		rounds.Round, time.Time, group.MessageID, error)
 
 	// GetGroups returns a list of all registered GroupChat IDs.
 	GetGroups() []*id.ID
@@ -114,7 +115,7 @@ type groupE2e interface {
 // methods needed by GroupChat
 type groupCmix interface {
 	SendMany(messages []cmix.TargetedCmixMessage, p cmix.CMIXParams) (
-		id.Round, []ephemeral.Id, error)
+		rounds.Round, []ephemeral.Id, error)
 	AddService(
 		clientID *id.ID, newService message.Service, response message.Processor)
 	DeleteService(
@@ -126,7 +127,7 @@ type groupCmix interface {
 // needed by GroupChat
 type groupE2eHandler interface {
 	SendE2E(mt catalog.MessageType, recipient *id.ID, payload []byte,
-		params e2e.Params) ([]id.Round, crypto.MessageID, time.Time, error)
+		params e2e.Params) (cryptoE2e.SendReport, error)
 	RegisterListener(senderID *id.ID, messageType catalog.MessageType,
 		newListener receive.Listener) receive.ListenerID
 	AddService(tag string, processor message.Processor) error
diff --git a/groupChat/internalFormat.go b/groupChat/internalFormat.go
index e8fd69df643856b49a217a7ae0602ce7e741e363..51e98eb6960125334c05aa7f00e771b86da14386 100644
--- a/groupChat/internalFormat.go
+++ b/groupChat/internalFormat.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package groupChat
 
diff --git a/groupChat/internalFormat_test.go b/groupChat/internalFormat_test.go
index 7c2d415ee68e041842d127293ccdf97b2506d1cf..2a717aa5302dc507c60e9708e132c4c634e01faa 100644
--- a/groupChat/internalFormat_test.go
+++ b/groupChat/internalFormat_test.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package groupChat
 
diff --git a/groupChat/makeGroup.go b/groupChat/makeGroup.go
index b7db0a1033a848009ac63e58f0357920382136fa..aeaea8efc6de93e130204137bf9096d56f8eead0 100644
--- a/groupChat/makeGroup.go
+++ b/groupChat/makeGroup.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package groupChat
 
diff --git a/groupChat/makeGroup_test.go b/groupChat/makeGroup_test.go
index 737ca52cae289725ccd264abe90020e5b0c64ea2..34596d71e8c38d5a5ee28a17c7e7edfe606a1f25 100644
--- a/groupChat/makeGroup_test.go
+++ b/groupChat/makeGroup_test.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package groupChat
 
diff --git a/groupChat/manager.go b/groupChat/manager.go
index 0e8fb03645afbe26e4de93dd3e19fa9bf7221342..82b7d432636713788d8e33a4d4e9a3b9db0034fb 100644
--- a/groupChat/manager.go
+++ b/groupChat/manager.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package groupChat
 
diff --git a/groupChat/manager_test.go b/groupChat/manager_test.go
index c5edaeedf6763e33e3193827ec163e07f179e086..7cb7d2f59d3b4550286531d458921c3d9f96f08a 100644
--- a/groupChat/manager_test.go
+++ b/groupChat/manager_test.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package groupChat
 
diff --git a/groupChat/messageReceive.go b/groupChat/messageReceive.go
index c605d7860b096d82411ef5d1ba2b3c9e1604968e..82cbc37d30123496353a4311e986206b47b65642 100644
--- a/groupChat/messageReceive.go
+++ b/groupChat/messageReceive.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package groupChat
 
diff --git a/groupChat/messageReceive_test.go b/groupChat/messageReceive_test.go
index 701890bcedd5476d529f3dd1d2e42a31e0e979ce..4ba6ece72aab9e4c92a36b84fc4dd3ae3ea86eff 100644
--- a/groupChat/messageReceive_test.go
+++ b/groupChat/messageReceive_test.go
@@ -1,9 +1,10 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package groupChat
 
 import (
diff --git a/groupChat/messenger_test.go b/groupChat/messenger_test.go
index 56436ad65481bc4520d76770604cbd13364e9b8a..1ebf8d4d696cf05881c317ffafa3a5f4fd03cc5d 100644
--- a/groupChat/messenger_test.go
+++ b/groupChat/messenger_test.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package groupChat
 
 import (
diff --git a/groupChat/networkManager_test.go b/groupChat/networkManager_test.go
index a6df5a6427d976a21a652d89db81e8941348f34e..e87b3f655bca1e2d5ccbf3d6547a25c1b1ac471d 100644
--- a/groupChat/networkManager_test.go
+++ b/groupChat/networkManager_test.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package groupChat
 
 import (
@@ -37,9 +44,9 @@ func newTestNetworkManager(sendErr int) cmix.Client {
 	}
 }
 
-func (tnm *testNetworkManager) SendMany(messages []cmix.TargetedCmixMessage, _ cmix.CMIXParams) (id.Round, []ephemeral.Id, error) {
+func (tnm *testNetworkManager) SendMany(messages []cmix.TargetedCmixMessage, _ cmix.CMIXParams) (rounds.Round, []ephemeral.Id, error) {
 	if tnm.sendErr == 1 {
-		return 0, nil, errors.New("SendManyCMIX error")
+		return rounds.Round{}, nil, errors.New("SendManyCMIX error")
 	}
 
 	tnm.Lock()
@@ -56,7 +63,7 @@ func (tnm *testNetworkManager) SendMany(messages []cmix.TargetedCmixMessage, _ c
 		receiveMessages = append(receiveMessages, receiveMsg)
 	}
 	tnm.receptionMessages = append(tnm.receptionMessages, receiveMessages)
-	return 0, nil, nil
+	return rounds.Round{}, nil, nil
 }
 
 func (*testNetworkManager) AddService(*id.ID, message.Service, message.Processor)    {}
@@ -71,7 +78,14 @@ func (tnm *testNetworkManager) Follow(report cmix.ClientErrorReport) (stoppable.
 	panic("implement me")
 }
 
-func (tnm *testNetworkManager) Send(recipient *id.ID, fingerprint format.Fingerprint, service message.Service, payload, mac []byte, cmixParams cmix.CMIXParams) (id.Round, ephemeral.Id, error) {
+func (tnm *testNetworkManager) SendWithAssembler(recipient *id.ID,
+	assembler cmix.MessageAssembler, cmixParams cmix.CMIXParams) (rounds.Round,
+	ephemeral.Id, error) {
+	//TODO implement me
+	panic("implement me")
+}
+
+func (tnm *testNetworkManager) Send(recipient *id.ID, fingerprint format.Fingerprint, service message.Service, payload, mac []byte, cmixParams cmix.CMIXParams) (rounds.Round, ephemeral.Id, error) {
 	//TODO implement me
 	panic("implement me")
 }
@@ -156,7 +170,7 @@ func (tnm *testNetworkManager) TriggerNodeRegistration(nid *id.ID) {
 	panic("implement me")
 }
 
-func (tnm *testNetworkManager) GetRoundResults(timeout time.Duration, roundCallback cmix.RoundEventCallback, roundList ...id.Round) error {
+func (tnm *testNetworkManager) GetRoundResults(timeout time.Duration, roundCallback cmix.RoundEventCallback, roundList ...id.Round) {
 	//TODO implement me
 	panic("implement me")
 }
diff --git a/groupChat/processor.go b/groupChat/processor.go
index fa115755751a6e5d6a989c9456895220ec5336ef..f397046a924b66808b115b35f1f41221f876d175 100644
--- a/groupChat/processor.go
+++ b/groupChat/processor.go
@@ -1,8 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package groupChat
diff --git a/groupChat/publicFormat.go b/groupChat/publicFormat.go
index ab88d9e09f9c7e5110404fca5fc473070b45c088..eb72300f480c57701149b1211df546a9916f95de 100644
--- a/groupChat/publicFormat.go
+++ b/groupChat/publicFormat.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package groupChat
 
diff --git a/groupChat/publicFormat_test.go b/groupChat/publicFormat_test.go
index ceb1ba2ec32ea0f6112b33a53218af557c0c2706..8c734de5a0223747e3dfa44938ec19fd1185684e 100644
--- a/groupChat/publicFormat_test.go
+++ b/groupChat/publicFormat_test.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package groupChat
 
 import (
diff --git a/groupChat/receive.go b/groupChat/receive.go
index aecbfad2ee37d9242a70e3e5f1a8d21773854340..004f7f370224c7df6368705f86b5f33eb4a3e2fd 100644
--- a/groupChat/receive.go
+++ b/groupChat/receive.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package groupChat
 
diff --git a/groupChat/receiveRequest.go b/groupChat/receiveRequest.go
index 104a326f1101f966510daea00db75a0c613efa67..e88aa858210d7bab639c672caf3e69cf0e2a9e2e 100644
--- a/groupChat/receiveRequest.go
+++ b/groupChat/receiveRequest.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package groupChat
 
diff --git a/groupChat/receiveRequest_test.go b/groupChat/receiveRequest_test.go
index d1283b8955f319e526322882d5b609e96282c3c2..e3611bab8193e2b87001578d4df640101c71b2dc 100644
--- a/groupChat/receiveRequest_test.go
+++ b/groupChat/receiveRequest_test.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package groupChat
 
diff --git a/groupChat/receive_test.go b/groupChat/receive_test.go
index bc35aee1d8280ebfbf261485b58a6a28476d04fc..be3a3bbff5c56c38a9ef3f910a47c18c1e0eddfe 100644
--- a/groupChat/receive_test.go
+++ b/groupChat/receive_test.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package groupChat
 
diff --git a/groupChat/send.go b/groupChat/send.go
index efa0e11639c261256fd200cbaac31389b9d7168f..2f1b17c167b13f5c06dbbc3fd3223dc6c1ef4e0f 100644
--- a/groupChat/send.go
+++ b/groupChat/send.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package groupChat
 
@@ -12,6 +12,7 @@ import (
 	jww "github.com/spf13/jwalterweatherman"
 	"gitlab.com/elixxir/client/cmix"
 	"gitlab.com/elixxir/client/cmix/message"
+	"gitlab.com/elixxir/client/cmix/rounds"
 	gs "gitlab.com/elixxir/client/groupChat/groupStore"
 	"gitlab.com/elixxir/crypto/cyclic"
 	"gitlab.com/elixxir/crypto/group"
@@ -46,7 +47,7 @@ const (
 // Send sends a message to all group members using Cmix.SendMany.
 // The send fails if the message is too long.
 func (m *manager) Send(groupID *id.ID, tag string, message []byte) (
-	id.Round, time.Time, group.MessageID, error) {
+	rounds.Round, time.Time, group.MessageID, error) {
 
 	if tag == "" {
 		tag = defaultServiceTag
@@ -55,7 +56,7 @@ func (m *manager) Send(groupID *id.ID, tag string, message []byte) (
 	// Get the relevant group
 	g, exists := m.GetGroup(groupID)
 	if !exists {
-		return 0, time.Time{}, group.MessageID{},
+		return rounds.Round{}, time.Time{}, group.MessageID{},
 			errors.Errorf(newNoGroupErr, groupID)
 	}
 
@@ -65,7 +66,7 @@ func (m *manager) Send(groupID *id.ID, tag string, message []byte) (
 	// Create a cMix message for each group member
 	groupMessages, err := m.newMessages(g, tag, message, timeNow)
 	if err != nil {
-		return 0, time.Time{}, group.MessageID{},
+		return rounds.Round{}, time.Time{}, group.MessageID{},
 			errors.Errorf(newCmixMsgErr, g.Name, g.ID, err)
 	}
 
@@ -73,7 +74,7 @@ func (m *manager) Send(groupID *id.ID, tag string, message []byte) (
 	msgId, err := getGroupMessageId(
 		m.getE2eGroup(), groupID, m.getReceptionIdentity().ID, timeNow, message)
 	if err != nil {
-		return 0, time.Time{}, group.MessageID{}, err
+		return rounds.Round{}, time.Time{}, group.MessageID{}, err
 	}
 
 	// Send all the groupMessages
@@ -81,7 +82,7 @@ func (m *manager) Send(groupID *id.ID, tag string, message []byte) (
 	param.DebugTag = "group.Message"
 	rid, _, err := m.getCMix().SendMany(groupMessages, param)
 	if err != nil {
-		return 0, time.Time{}, group.MessageID{},
+		return rounds.Round{}, time.Time{}, group.MessageID{},
 			errors.Errorf(sendManyCmixErr, m.getReceptionIdentity().ID, g.Name, g.ID, err)
 	}
 
diff --git a/groupChat/sendRequests.go b/groupChat/sendRequests.go
index b28985361e09183b6b4d807e10c770b454386bda..36046527379d67151a69f588e773b03f6758f87d 100644
--- a/groupChat/sendRequests.go
+++ b/groupChat/sendRequests.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package groupChat
 
@@ -120,13 +120,13 @@ func (m *manager) sendRequest(memberID *id.ID, request []byte) ([]id.Round, erro
 	p.LastServiceTag = catalog.GroupRq
 	p.DebugTag = "group.Request"
 
-	rounds, _, _, err := m.getE2eHandler().SendE2E(
+	sendReport, err := m.getE2eHandler().SendE2E(
 		catalog.GroupCreationRequest, memberID, request, p)
 	if err != nil {
 		return nil, errors.Errorf(sendE2eErr, memberID, err)
 	}
 
-	return rounds, nil
+	return sendReport.RoundList, nil
 }
 
 // roundIdMap2List converts the map of round IDs to a list of round IDs.
diff --git a/groupChat/sendRequests_test.go b/groupChat/sendRequests_test.go
index bb2589689e40f70b997ddd250da33c50f0c2c99a..3878e52a4d81e80523c41d3bdc2baf41281ab39c 100644
--- a/groupChat/sendRequests_test.go
+++ b/groupChat/sendRequests_test.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package groupChat
 
diff --git a/groupChat/send_test.go b/groupChat/send_test.go
index be68cb2e8bccca341785038e8596302ba63ba9d5..5ecaa63efdca7f1d461fb59c67908988370accc5 100644
--- a/groupChat/send_test.go
+++ b/groupChat/send_test.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package groupChat
 
@@ -56,7 +56,7 @@ func Test_manager_Send(t *testing.T) {
 		reception.Process(msg, receptionID.EphemeralIdentity{
 			EphId: ephemeral.Id{1, 2, 3}, Source: &id.ID{4, 5, 6},
 		},
-			rounds.Round{ID: roundId, Timestamps: timestamps})
+			rounds.Round{ID: roundId.ID, Timestamps: timestamps})
 		select {
 		case result := <-msgChan:
 			if !result.SenderID.Cmp(m.getReceptionIdentity().ID) {
diff --git a/groupChat/service.go b/groupChat/service.go
index d2a5916aaa7975a8d20065f88ce0a9047bbbed74..eb57bc38f39c010fd1525a48e69720bd9b82b033 100644
--- a/groupChat/service.go
+++ b/groupChat/service.go
@@ -1,8 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package groupChat
diff --git a/groupChat/session_test.go b/groupChat/session_test.go
index 15877e7af4c0afcb9a7b8276810ebdd21b91eb26..a61cf8b510ed05b1d7fee252e31dd314f03097d0 100644
--- a/groupChat/session_test.go
+++ b/groupChat/session_test.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package groupChat
 
 import (
diff --git a/groupChat/utils_test.go b/groupChat/utils_test.go
index 024d4c02446fd632937bc87f5d626a20ae5161de..98e63bcf98fa3a658a95b28c16b626c3411ccbcc 100644
--- a/groupChat/utils_test.go
+++ b/groupChat/utils_test.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package groupChat
 
diff --git a/groupChat/wrapper.go b/groupChat/wrapper.go
index 6a3e91220d29cef35769f7aff86cef5899a619cc..462811c8d20f606353c419f61bd079e2a8480875 100644
--- a/groupChat/wrapper.go
+++ b/groupChat/wrapper.go
@@ -1,13 +1,14 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package groupChat
 
 import (
+	"gitlab.com/elixxir/client/cmix/rounds"
 	gs "gitlab.com/elixxir/client/groupChat/groupStore"
 	"gitlab.com/elixxir/crypto/group"
 	"gitlab.com/xx_network/primitives/id"
@@ -53,7 +54,7 @@ func (w *Wrapper) LeaveGroup(groupID *id.ID) error {
 
 // Send calls GroupChat.Send.
 func (w *Wrapper) Send(groupID *id.ID, message []byte, tag string) (
-	id.Round, time.Time, group.MessageID, error) {
+	rounds.Round, time.Time, group.MessageID, error) {
 	return w.gc.Send(groupID, tag, message)
 }
 
diff --git a/interfaces/auth.go b/interfaces/auth.go
index 60ba0d311342b154238caf251d2eb0c22f339d53..fe022dfe471a8696adc56f765ff6a6e96db2418b 100644
--- a/interfaces/auth.go
+++ b/interfaces/auth.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package interfaces
 
diff --git a/interfaces/clientError.go b/interfaces/clientError.go
index 39c6706c7fb83b1df657c46d46f733c55c9b562d..86b55ac9f959abc6bef07c5870c71a94a78fa0a8 100644
--- a/interfaces/clientError.go
+++ b/interfaces/clientError.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package interfaces
 
 type ClientError struct {
diff --git a/interfaces/ephemeral.go b/interfaces/ephemeral.go
index 4d0e7f926f5a3a863a49a51e499dbde5146d7f94..57523cb5e123322a41f551d4d6aab3c68b00f042 100644
--- a/interfaces/ephemeral.go
+++ b/interfaces/ephemeral.go
@@ -1,8 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package interfaces
diff --git a/interfaces/healthTracker.go b/interfaces/healthTracker.go
index 0d746d50f73bc1215201c413e5d6d83e54bbbb55..995df5ce21933c8228becc225a8fcd800a6511cf 100644
--- a/interfaces/healthTracker.go
+++ b/interfaces/healthTracker.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package interfaces
 
diff --git a/interfaces/networkManager.go b/interfaces/networkManager.go
deleted file mode 100644
index 2139e9597c6a4cdc51714e47308d6aa91d3481c5..0000000000000000000000000000000000000000
--- a/interfaces/networkManager.go
+++ /dev/null
@@ -1,244 +0,0 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
-
-package interfaces
-
-import (
-	"time"
-
-	"gitlab.com/elixxir/comms/network"
-	"gitlab.com/xx_network/comms/connect"
-	"gitlab.com/xx_network/primitives/ndf"
-
-	"gitlab.com/elixxir/client/cmix"
-	"gitlab.com/elixxir/client/cmix/message"
-	"gitlab.com/elixxir/client/stoppable"
-	"gitlab.com/elixxir/comms/mixmessages"
-	"gitlab.com/elixxir/primitives/format"
-	"gitlab.com/xx_network/primitives/id"
-	"gitlab.com/xx_network/primitives/id/ephemeral"
-)
-
-type NetworkManager interface {
-	// Follow starts the tracking of the network in a new thread.
-	// Errors that occur are reported on the ClientErrorReport function if
-	// passed. The returned stopable can be used to stop the follower.
-	// Only one follower may run at a time.
-	Follow(report ClientErrorReport) (stoppable.Stoppable, error)
-
-	/*===Sending==========================================================*/
-
-	// SendCMIX sends a "raw" CMIX message payload to the provided
-	// recipient.  Returns the round ID of the round the payload
-	// was sent or an error if it fails.
-	SendCMIX(message format.Message, recipient *id.ID, p cmix.Params) (
-		id.Round, ephemeral.Id, error)
-
-	// SendManyCMIX sends many "raw" cMix message payloads to each
-	// of the provided recipients. Used to send messages in group
-	// chats. Metadata is NOT as well protected with this call and
-	// can leak data about yourself. Should be replaced with
-	// multiple uses of SendCmix in most cases. Returns the round
-	// ID of the round the payload was sent or an error if it
-	// fails.
-	// WARNING: Potentially Unsafe
-	SendManyCMIX(messages []cmix.TargetedCmixMessage, p cmix.Params) (
-		id.Round, []ephemeral.Id, error)
-
-	/*===Message Reception================================================*/
-	/* Identities are all network identities which the client is currently
-	trying to pick up message on. An identity must be added
-	to receive messages, fake ones will be used to poll the network
-	if none are present. On creation of the network handler, the identity in
-	session storage will be automatically added*/
-
-	// AddIdentity adds an identity to be tracked
-	// If persistent is false, the identity will not be stored to disk and
-	// will be dropped on reload.
-	AddIdentity(id *id.ID, validUntil time.Time, persistent bool) error
-	// RemoveIdentity removes a currently tracked identity.
-	RemoveIdentity(id *id.ID)
-
-	/* Fingerprints are the primary mechanism of identifying a
-	picked up message over cMix. They are a unique one time use
-	255 bit vector generally associated with a specific encryption
-	key, but can be used for an alternative protocol.When
-	registering a fingerprint, a MessageProcessor is registered to
-	handle the message.*/
-
-	// AddFingerprint - Adds a fingerprint which will be handled by a
-	// specific processor for messages received by the given identity
-	AddFingerprint(identity *id.ID, fingerprint format.Fingerprint,
-		mp message.Processor) error
-
-	// DeleteFingerprint deletes a single fingerprint associated
-	// with the given identity if it exists
-
-	DeleteFingerprint(identity *id.ID, fingerprint format.Fingerprint)
-	// DeleteClientFingerprints deletes al fingerprint associated
-	// with the given identity if it exists
-	DeleteClientFingerprints(identity *id.ID)
-
-	/* trigger - predefined hash based tags appended to all cMix messages
-	which, though trial hashing, are used to determine if a message applies
-	to this client
-
-	Triggers are used for 2 purposes - They can be processed by the
-	notifications system, or can be used to implement custom non fingerprint
-	processing of payloads. I.E. key negotiation, broadcast negotiation
-
-	A tag is appended to the message of the format tag =
-	H(H(messageContents), preimage) and trial hashing is used to
-	determine if a message adheres to a tag.
-
-	WARNING: If a preimage is known by an adversary, they can
-	determine which messages are for the client on reception
-	(which is normally hidden due to collision between ephemeral
-	IDs.
-
-	Due to the extra overhead of trial hashing, triggers are
-	processed after fingerprints.  If a fingerprint match occurs
-	on the message, triggers will not be handled.
-
-	Triggers are address to the session. When starting a new
-	client, all triggers must be re-added before
-	StartNetworkFollower is called.
-	*/
-
-	// AddTrigger - Adds a trigger which can call a message
-	// handing function or be used for notifications. Multiple
-	// triggers can be registered for the same preimage.
-	//   preimage - the preimage which is triggered on
-	//   type - a descriptive string of the trigger. Generally
-	//          used in notifications
-	//   source - a byte buffer of related data. Generally used in
-	//            notifications.
-	//     Example: Sender ID
-	AddTrigger(identity *id.ID, newTrigger message.Service,
-		response message.Processor)
-
-	// DeleteTrigger - If only a single response is associated with the
-	// preimage, the entire preimage is removed. If there is more than one
-	// response, only the given response is removed if nil is passed in for
-	// response, all triggers for the preimage will be removed
-	DeleteTrigger(identity *id.ID, preimage Preimage,
-		response message.Processor) error
-
-	// DeleteClientTriggers - deletes all triggers assoseated with
-	// the given identity
-	DeleteClientTriggers(identity *id.ID)
-
-	// TrackServices - Registers a callback which will get called
-	// every time triggers change.
-	// It will receive the triggers list every time it is modified.
-	// Will only get callbacks while the Network Follower is running.
-	// Multiple trackTriggers can be registered
-	TrackServices(message.ServicesTracker)
-
-	/* In inProcess */
-	// it is possible to receive a message over cMix before the
-	// fingerprints or triggers are registered. As a result, when
-	// handling fails, messages are put in the inProcess que for a
-	// set number of retries.
-
-	// CheckInProgressMessages - retry processing all messages in check in
-	// progress messages. Call this after adding fingerprints or triggers
-	//while the follower is running.
-	CheckInProgressMessages()
-
-	/*===Nodes============================================================*/
-	/* Keys must be registed with nodes in order to send messages
-	throug them.  this process is in general automatically handled
-	by the Network Manager*/
-
-	// HasNode can be used to determine if a keying relationship
-	// exists with a node.
-	HasNode(nid *id.ID) bool
-
-	// NumRegisteredNodes Returns the total number of nodes we have a keying
-	// relationship with
-	NumRegisteredNodes() int
-
-	// TriggerNodeRegistration triggers the generation of a keying
-	// relationship with a given node
-	TriggerNodeRegistration(nid *id.ID)
-
-	/*===Historical Rounds================================================*/
-	/* A complete set of round info is not kept on the client, and sometimes
-	the network will need to be queried to get round info. Historical rounds
-	is the system internal to the Network Manager to do this.
-	It can be used externally as well.*/
-
-	// LookupHistoricalRound - looks up the passed historical round on the
-	// network
-	LookupHistoricalRound(rid id.Round,
-		callback func(info *mixmessages.RoundInfo,
-		success bool)) error
-
-	/*===Sender===========================================================*/
-	/* The sender handles sending comms to the network. It tracks
-	connections to gateways and handles proxying to gateways for
-	targeted comms. It can be used externally to contact gateway
-	directly, bypassing the majority of the network package*/
-
-	// SendToAny can be used to send the comm to any gateway in the network.
-	SendToAny(sendFunc func(host *connect.Host) (interface{}, error),
-		stop *stoppable.Single) (interface{}, error)
-
-	// SendToPreferred sends to a specific gateway, doing so through another
-	// gateway as a proxy if not directly connected.
-	SendToPreferred(targets []*id.ID, sendFunc func(host *connect.Host,
-		target *id.ID, timeout time.Duration) (interface{}, error),
-		stop *stoppable.Single, timeout time.Duration) (interface{},
-		error)
-
-	// SetGatewayFilter sets a function which will be used to
-	// filter gateways before connecting.
-	SetGatewayFilter(f func(map[id.ID]int,
-		*ndf.NetworkDefinition) map[id.ID]int)
-
-	// GetHostParams - returns the host params used when
-	// connectign to gateways
-	GetHostParams() connect.HostParams
-
-	/*===Address Space====================================================*/
-	// The network compasses identities into a smaller address
-	// space to cause collisions and hide the actual recipient of
-	// messages. These functions allow for the tracking of this
-	// addresses space. In general, address space issues are
-	// completely handled by the network package
-
-	// GetAddressSpace GetAddressSize returns the current address
-	// size of IDs. Blocks until an address size is known.
-	GetAddressSpace() uint8
-
-	// RegisterAddressSpaceNotification returns a channel that
-	// will trigger for every address space size update. The
-	// provided tag is the unique ID for the channel. Returns an
-	// error if the tag is already used.
-	RegisterAddressSpaceNotification(tag string) (chan uint8, error)
-
-	// UnregisterAddressSpaceNotification stops broadcasting
-	// address space size updates on the channel with the
-	// specified tag.
-	UnregisterAddressSpaceNotification(tag string)
-
-	/*===Accessors========================================================*/
-
-	// GetInstance returns the network instance object, which tracks the
-	// state of the network
-	GetInstance() *network.Instance
-
-	// GetHealthTracker returns the health tracker, which using a polling or
-	// event api lets you determine if network following is functioning
-	GetHealthTracker() HealthTracker
-
-	// GetVerboseRounds returns stringification of verbose round info
-	GetVerboseRounds() string
-}
-
-type Preimage [32]byte
diff --git a/interfaces/restoreContacts.go b/interfaces/restoreContacts.go
index defc6877b4310d964425b6f2555df64a2a5a28d9..82ca65b825d5081baff773519d6d0c0eced6a39c 100644
--- a/interfaces/restoreContacts.go
+++ b/interfaces/restoreContacts.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package interfaces
 
diff --git a/interfaces/roundEvents.go b/interfaces/roundEvents.go
index 7228649def38a6199a7650df1b811373ad7f0307..a2113d6f5fe86959aa365729eac5c8ae2bd8f3e1 100644
--- a/interfaces/roundEvents.go
+++ b/interfaces/roundEvents.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package interfaces
 
diff --git a/interfaces/sidh/sidh.go b/interfaces/sidh/sidh.go
index 81468e4be1f4e48ee50cd20713cd08eab5be3f0a..ff1ad9c4f63a063ce54bf67e2759e56b374054d8 100644
--- a/interfaces/sidh/sidh.go
+++ b/interfaces/sidh/sidh.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package interfaces
 
 import "github.com/cloudflare/circl/dh/sidh"
diff --git a/main.go b/main.go
index 47a38ce28d8f06cb2c16d1aba035b3a9c393caad..ac80eb9a1fc5411c091bd1f3bad27b89e90114d7 100644
--- a/main.go
+++ b/main.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package main
 
diff --git a/registration/permissioning.go b/registration/permissioning.go
index cab953a8472df368a6bc7dd72218a5e49796c2c8..293c39010e2074c3297d306303d9d4b163f8d3f3 100644
--- a/registration/permissioning.go
+++ b/registration/permissioning.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package registration
 
diff --git a/registration/permissioning_test.go b/registration/permissioning_test.go
index 616ab9393b868bf4da25e69976a3d316adc23d84..94d2bacf0cfa75789016efaca3b629c26bf6cac1 100644
--- a/registration/permissioning_test.go
+++ b/registration/permissioning_test.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package registration
 
diff --git a/registration/register.go b/registration/register.go
index 57b6cf8f2003b0323d96d9b53aff9dc6e0f1ac2c..56986c809660edcf23fadf0947afa2f8aa5fc485 100644
--- a/registration/register.go
+++ b/registration/register.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package registration
 
@@ -62,14 +62,6 @@ func register(comms registrationMessageSender, host *connect.Host,
 			"reception confirmation message")
 	}
 
-	transmissionConfirmation := &pb.ClientRegistrationConfirmation{}
-	err = proto.Unmarshal(response.GetClientReceptionConfirmation().
-		ClientRegistrationConfirmation, transmissionConfirmation)
-	if err != nil {
-		return nil, nil, 0, errors.WithMessage(err, "Failed to unmarshal "+
-			"transmission confirmation message")
-	}
-
 	// Verify reception signature
 	receptionSignature := response.GetClientReceptionConfirmation().
 		GetRegistrarSignature().Signature
@@ -80,6 +72,15 @@ func register(comms registrationMessageSender, host *connect.Host,
 		return nil, nil, 0, errors.WithMessage(err, "Failed to verify reception signature")
 	}
 
+	// Unmarshal transmission confirmation
+	transmissionConfirmation := &pb.ClientRegistrationConfirmation{}
+	err = proto.Unmarshal(response.GetClientTransmissionConfirmation().
+		ClientRegistrationConfirmation, transmissionConfirmation)
+	if err != nil {
+		return nil, nil, 0, errors.WithMessage(err, "Failed to unmarshal "+
+			"transmission confirmation message")
+	}
+
 	// Verify transmission signature
 	transmissionSignature := response.GetClientTransmissionConfirmation().
 		GetRegistrarSignature().Signature
diff --git a/registration/register_test.go b/registration/register_test.go
index d7b95baf4e4581ca96f56605e43eb043a628e46e..8cec2bfb92f215640de1206141d473a47eea9601 100644
--- a/registration/register_test.go
+++ b/registration/register_test.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package registration
 
diff --git a/restlike/compileProtobuf.sh b/restlike/compileProtobuf.sh
new file mode 100644
index 0000000000000000000000000000000000000000..1e6fda1ef503db58983b3756bc578760e7ddaaec
--- /dev/null
+++ b/restlike/compileProtobuf.sh
@@ -0,0 +1,14 @@
+#!/bin/bash
+################################################################################
+## Copyright © 2022 xx foundation                                             ##
+##                                                                            ##
+## Use of this source code is governed by a license that can be found in the  ##
+## LICENSE file.                                                              ##
+################################################################################
+
+# This script will compile the Protobuf file to a Go file (pb.go).
+# This is meant to be called from the top level of the repo.
+
+cd ./restlike/ || return
+
+protoc --go_out=. --go_opt=paths=source_relative ./restLikeMessages.proto
diff --git a/restlike/connect/receiver.go b/restlike/connect/receiver.go
index d6e87c57489a4235cd0e225fb38c4c87dad4afc3..20ad79df76dd9003ac6d7e43cbae18185faa8217 100644
--- a/restlike/connect/receiver.go
+++ b/restlike/connect/receiver.go
@@ -1,7 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2022 Privategrity Corporation                                   /
-//                                                                             /
-// All rights reserved.                                                        /
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package connect
@@ -55,7 +56,7 @@ func respond(response *restlike.Message, conn connect.Connection) error {
 	}
 
 	// TODO: Parameterize params
-	_, _, _, err = conn.SendE2E(catalog.XxMessage, payload, e2e.GetDefaultParams())
+	_, err = conn.SendE2E(catalog.XxMessage, payload, e2e.GetDefaultParams())
 	if err != nil {
 		return errors.Errorf("unable to send restlike response message: %+v", err)
 	}
diff --git a/restlike/connect/receiver_test.go b/restlike/connect/receiver_test.go
index 723ec019fbedf4532b4f2a3d2bf3f66be51d36b1..409dcd9e3814892c229b097677f849bd038ad36d 100644
--- a/restlike/connect/receiver_test.go
+++ b/restlike/connect/receiver_test.go
@@ -1,7 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2022 Privategrity Corporation                                   /
-//                                                                             /
-// All rights reserved.                                                        /
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package connect
diff --git a/restlike/connect/request.go b/restlike/connect/request.go
index 4ea32656a2f3716481153e1955d0435311b61244..bd2ac8d978b1dcc89cd301f8a058c44c72ae76f9 100644
--- a/restlike/connect/request.go
+++ b/restlike/connect/request.go
@@ -1,7 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2022 Privategrity Corporation                                   /
-//                                                                             /
-// All rights reserved.                                                        /
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package connect
@@ -49,7 +50,8 @@ func (s *Request) Request(method restlike.Method, path restlike.URI,
 	s.Net.RegisterListener(catalog.XxMessage, &response{responseCallback: cb})
 
 	// Transmit the Message
-	_, _, _, err = s.Net.SendE2E(catalog.XxMessage, msg, e2eParams)
+	// fixme: should this use the key residue?
+	_, err = s.Net.SendE2E(catalog.XxMessage, msg, e2eParams)
 	if err != nil {
 		return nil, err
 	}
@@ -84,6 +86,6 @@ func (s *Request) AsyncRequest(method restlike.Method, path restlike.URI,
 	s.Net.RegisterListener(catalog.XxMessage, &response{responseCallback: cb})
 
 	// Transmit the Message
-	_, _, _, err = s.Net.SendE2E(catalog.XxMessage, msg, e2eParams)
+	_, err = s.Net.SendE2E(catalog.XxMessage, msg, e2eParams)
 	return err
 }
diff --git a/restlike/connect/response.go b/restlike/connect/response.go
index 99042d7c4bd4947a2f2eed560f4fef8114998d9d..83d55ddea39ed9e051953dd2c1b4a3f8910ef39b 100644
--- a/restlike/connect/response.go
+++ b/restlike/connect/response.go
@@ -1,7 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2022 Privategrity Corporation                                   /
-//                                                                             /
-// All rights reserved.                                                        /
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package connect
diff --git a/restlike/connect/response_test.go b/restlike/connect/response_test.go
index f3db1ba40f2024b83522c2d9a5c840d5e4691da4..d82947861901dcf3039dbd1628b948d5c44baea5 100644
--- a/restlike/connect/response_test.go
+++ b/restlike/connect/response_test.go
@@ -1,7 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2022 Privategrity Corporation                                   /
-//                                                                             /
-// All rights reserved.                                                        /
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package connect
diff --git a/restlike/connect/server.go b/restlike/connect/server.go
index 7438b41d7ffaa5edb99e7d3f99913a0250921ee9..47d3955b4d0d33763ae63c2f9a733f7678dce8c6 100644
--- a/restlike/connect/server.go
+++ b/restlike/connect/server.go
@@ -1,7 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2022 Privategrity Corporation                                   /
-//                                                                             /
-// All rights reserved.                                                        /
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package connect
diff --git a/restlike/generateProto.sh b/restlike/generateProto.sh
deleted file mode 100755
index 67b6d293f6f4e6a68eff4162a42acb242129cd18..0000000000000000000000000000000000000000
--- a/restlike/generateProto.sh
+++ /dev/null
@@ -1,3 +0,0 @@
-#!/bin/bash
-
-protoc --go_out=paths=source_relative:. restlike/restLikeMessages.proto
diff --git a/restlike/restLikeMessages.pb.go b/restlike/restLikeMessages.pb.go
index c6666a5d08dd3c0a086a100a19ca0a74f630af79..674580e375c72f057883a4e6f27a7a5466d3749e 100644
--- a/restlike/restLikeMessages.pb.go
+++ b/restlike/restLikeMessages.pb.go
@@ -1,15 +1,15 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 // Code generated by protoc-gen-go. DO NOT EDIT.
 // versions:
 // 	protoc-gen-go v1.27.1
-// 	protoc        v3.19.1
-// source: restlike/restLikeMessages.proto
+// 	protoc        v3.15.6
+// source: restLikeMessages.proto
 
 package restlike
 
@@ -43,7 +43,7 @@ type Message struct {
 func (x *Message) Reset() {
 	*x = Message{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_restlike_restLikeMessages_proto_msgTypes[0]
+		mi := &file_restLikeMessages_proto_msgTypes[0]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -56,7 +56,7 @@ func (x *Message) String() string {
 func (*Message) ProtoMessage() {}
 
 func (x *Message) ProtoReflect() protoreflect.Message {
-	mi := &file_restlike_restLikeMessages_proto_msgTypes[0]
+	mi := &file_restLikeMessages_proto_msgTypes[0]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -69,7 +69,7 @@ func (x *Message) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use Message.ProtoReflect.Descriptor instead.
 func (*Message) Descriptor() ([]byte, []int) {
-	return file_restlike_restLikeMessages_proto_rawDescGZIP(), []int{0}
+	return file_restLikeMessages_proto_rawDescGZIP(), []int{0}
 }
 
 func (x *Message) GetContent() []byte {
@@ -124,7 +124,7 @@ type Headers struct {
 func (x *Headers) Reset() {
 	*x = Headers{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_restlike_restLikeMessages_proto_msgTypes[1]
+		mi := &file_restLikeMessages_proto_msgTypes[1]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -137,7 +137,7 @@ func (x *Headers) String() string {
 func (*Headers) ProtoMessage() {}
 
 func (x *Headers) ProtoReflect() protoreflect.Message {
-	mi := &file_restlike_restLikeMessages_proto_msgTypes[1]
+	mi := &file_restLikeMessages_proto_msgTypes[1]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -150,7 +150,7 @@ func (x *Headers) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use Headers.ProtoReflect.Descriptor instead.
 func (*Headers) Descriptor() ([]byte, []int) {
-	return file_restlike_restLikeMessages_proto_rawDescGZIP(), []int{1}
+	return file_restLikeMessages_proto_rawDescGZIP(), []int{1}
 }
 
 func (x *Headers) GetHeaders() []byte {
@@ -167,50 +167,49 @@ func (x *Headers) GetVersion() uint32 {
 	return 0
 }
 
-var File_restlike_restLikeMessages_proto protoreflect.FileDescriptor
+var File_restLikeMessages_proto protoreflect.FileDescriptor
 
-var file_restlike_restLikeMessages_proto_rawDesc = []byte{
-	0x0a, 0x1f, 0x72, 0x65, 0x73, 0x74, 0x6c, 0x69, 0x6b, 0x65, 0x2f, 0x72, 0x65, 0x73, 0x74, 0x4c,
-	0x69, 0x6b, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74,
-	0x6f, 0x12, 0x10, 0x72, 0x65, 0x73, 0x74, 0x4c, 0x69, 0x6b, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61,
-	0x67, 0x65, 0x73, 0x22, 0x98, 0x01, 0x0a, 0x07, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12,
-	0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c,
-	0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x12, 0x33, 0x0a, 0x07, 0x68, 0x65, 0x61,
-	0x64, 0x65, 0x72, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x72, 0x65, 0x73,
-	0x74, 0x4c, 0x69, 0x6b, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x48, 0x65,
-	0x61, 0x64, 0x65, 0x72, 0x73, 0x52, 0x07, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x12, 0x16,
-	0x0a, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06,
-	0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x69, 0x18, 0x04, 0x20,
-	0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x69, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f,
-	0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x3d,
-	0x0a, 0x07, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x68, 0x65, 0x61,
-	0x64, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x68, 0x65, 0x61, 0x64,
-	0x65, 0x72, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02,
-	0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x42, 0x24, 0x5a,
-	0x22, 0x67, 0x69, 0x74, 0x6c, 0x61, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x65, 0x6c, 0x69, 0x78,
-	0x78, 0x69, 0x72, 0x2f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x2f, 0x72, 0x65, 0x73, 0x74, 0x6c,
-	0x69, 0x6b, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+var file_restLikeMessages_proto_rawDesc = []byte{
+	0x0a, 0x16, 0x72, 0x65, 0x73, 0x74, 0x4c, 0x69, 0x6b, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67,
+	0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x08, 0x72, 0x65, 0x73, 0x74, 0x6c, 0x69,
+	0x6b, 0x65, 0x22, 0x90, 0x01, 0x0a, 0x07, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x18,
+	0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52,
+	0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x12, 0x2b, 0x0a, 0x07, 0x68, 0x65, 0x61, 0x64,
+	0x65, 0x72, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x72, 0x65, 0x73, 0x74,
+	0x6c, 0x69, 0x6b, 0x65, 0x2e, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x52, 0x07, 0x68, 0x65,
+	0x61, 0x64, 0x65, 0x72, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x18,
+	0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12, 0x10, 0x0a,
+	0x03, 0x75, 0x72, 0x69, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x69, 0x12,
+	0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05,
+	0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x3d, 0x0a, 0x07, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73,
+	0x12, 0x18, 0x0a, 0x07, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28,
+	0x0c, 0x52, 0x07, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65,
+	0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x76, 0x65, 0x72,
+	0x73, 0x69, 0x6f, 0x6e, 0x42, 0x24, 0x5a, 0x22, 0x67, 0x69, 0x74, 0x6c, 0x61, 0x62, 0x2e, 0x63,
+	0x6f, 0x6d, 0x2f, 0x65, 0x6c, 0x69, 0x78, 0x78, 0x69, 0x72, 0x2f, 0x63, 0x6c, 0x69, 0x65, 0x6e,
+	0x74, 0x2f, 0x72, 0x65, 0x73, 0x74, 0x6c, 0x69, 0x6b, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74,
+	0x6f, 0x33,
 }
 
 var (
-	file_restlike_restLikeMessages_proto_rawDescOnce sync.Once
-	file_restlike_restLikeMessages_proto_rawDescData = file_restlike_restLikeMessages_proto_rawDesc
+	file_restLikeMessages_proto_rawDescOnce sync.Once
+	file_restLikeMessages_proto_rawDescData = file_restLikeMessages_proto_rawDesc
 )
 
-func file_restlike_restLikeMessages_proto_rawDescGZIP() []byte {
-	file_restlike_restLikeMessages_proto_rawDescOnce.Do(func() {
-		file_restlike_restLikeMessages_proto_rawDescData = protoimpl.X.CompressGZIP(file_restlike_restLikeMessages_proto_rawDescData)
+func file_restLikeMessages_proto_rawDescGZIP() []byte {
+	file_restLikeMessages_proto_rawDescOnce.Do(func() {
+		file_restLikeMessages_proto_rawDescData = protoimpl.X.CompressGZIP(file_restLikeMessages_proto_rawDescData)
 	})
-	return file_restlike_restLikeMessages_proto_rawDescData
+	return file_restLikeMessages_proto_rawDescData
 }
 
-var file_restlike_restLikeMessages_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
-var file_restlike_restLikeMessages_proto_goTypes = []interface{}{
-	(*Message)(nil), // 0: restLikeMessages.Message
-	(*Headers)(nil), // 1: restLikeMessages.Headers
+var file_restLikeMessages_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
+var file_restLikeMessages_proto_goTypes = []interface{}{
+	(*Message)(nil), // 0: restlike.Message
+	(*Headers)(nil), // 1: restlike.Headers
 }
-var file_restlike_restLikeMessages_proto_depIdxs = []int32{
-	1, // 0: restLikeMessages.Message.headers:type_name -> restLikeMessages.Headers
+var file_restLikeMessages_proto_depIdxs = []int32{
+	1, // 0: restlike.Message.headers:type_name -> restlike.Headers
 	1, // [1:1] is the sub-list for method output_type
 	1, // [1:1] is the sub-list for method input_type
 	1, // [1:1] is the sub-list for extension type_name
@@ -218,13 +217,13 @@ var file_restlike_restLikeMessages_proto_depIdxs = []int32{
 	0, // [0:1] is the sub-list for field type_name
 }
 
-func init() { file_restlike_restLikeMessages_proto_init() }
-func file_restlike_restLikeMessages_proto_init() {
-	if File_restlike_restLikeMessages_proto != nil {
+func init() { file_restLikeMessages_proto_init() }
+func file_restLikeMessages_proto_init() {
+	if File_restLikeMessages_proto != nil {
 		return
 	}
 	if !protoimpl.UnsafeEnabled {
-		file_restlike_restLikeMessages_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
+		file_restLikeMessages_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
 			switch v := v.(*Message); i {
 			case 0:
 				return &v.state
@@ -236,7 +235,7 @@ func file_restlike_restLikeMessages_proto_init() {
 				return nil
 			}
 		}
-		file_restlike_restLikeMessages_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
+		file_restLikeMessages_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
 			switch v := v.(*Headers); i {
 			case 0:
 				return &v.state
@@ -253,18 +252,18 @@ func file_restlike_restLikeMessages_proto_init() {
 	out := protoimpl.TypeBuilder{
 		File: protoimpl.DescBuilder{
 			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
-			RawDescriptor: file_restlike_restLikeMessages_proto_rawDesc,
+			RawDescriptor: file_restLikeMessages_proto_rawDesc,
 			NumEnums:      0,
 			NumMessages:   2,
 			NumExtensions: 0,
 			NumServices:   0,
 		},
-		GoTypes:           file_restlike_restLikeMessages_proto_goTypes,
-		DependencyIndexes: file_restlike_restLikeMessages_proto_depIdxs,
-		MessageInfos:      file_restlike_restLikeMessages_proto_msgTypes,
+		GoTypes:           file_restLikeMessages_proto_goTypes,
+		DependencyIndexes: file_restLikeMessages_proto_depIdxs,
+		MessageInfos:      file_restLikeMessages_proto_msgTypes,
 	}.Build()
-	File_restlike_restLikeMessages_proto = out.File
-	file_restlike_restLikeMessages_proto_rawDesc = nil
-	file_restlike_restLikeMessages_proto_goTypes = nil
-	file_restlike_restLikeMessages_proto_depIdxs = nil
+	File_restLikeMessages_proto = out.File
+	file_restLikeMessages_proto_rawDesc = nil
+	file_restLikeMessages_proto_goTypes = nil
+	file_restLikeMessages_proto_depIdxs = nil
 }
diff --git a/restlike/restLikeMessages.proto b/restlike/restLikeMessages.proto
index 00156d5443904383deb89f64c391e0009741dc78..c0b37ee7652a1da6df2cca0a16deb4bf36c3e35f 100644
--- a/restlike/restLikeMessages.proto
+++ b/restlike/restLikeMessages.proto
@@ -1,12 +1,14 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 syntax = "proto3";
-package restLikeMessages;
+
+package restlike;
+
 option go_package = "gitlab.com/elixxir/client/restlike";
 
 // Message are used for sending to and receiving from a RestServer
diff --git a/restlike/single/receiver.go b/restlike/single/receiver.go
index f25268f8160d2d257121af560619c87997d87111..381bd923ebb120d7c1eb7c98c07de2ed18461a9f 100644
--- a/restlike/single/receiver.go
+++ b/restlike/single/receiver.go
@@ -1,7 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2022 Privategrity Corporation                                   /
-//                                                                             /
-// All rights reserved.                                                        /
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package single
diff --git a/restlike/single/receiver_test.go b/restlike/single/receiver_test.go
index 3b06c4c15691c049b1adcf684e9d29893baef121..7fe2bc6c02eddffc910b40f0728f00cc791dd136 100644
--- a/restlike/single/receiver_test.go
+++ b/restlike/single/receiver_test.go
@@ -1,7 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2022 Privategrity Corporation                                   /
-//                                                                             /
-// All rights reserved.                                                        /
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package single
diff --git a/restlike/single/request.go b/restlike/single/request.go
index 8a0b550867b5d2ebdaa43333fcf529940c701982..53dfcbce8a69a4811cc0f4cd6d91c49ae93f2451 100644
--- a/restlike/single/request.go
+++ b/restlike/single/request.go
@@ -1,7 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2022 Privategrity Corporation                                   /
-//                                                                             /
-// All rights reserved.                                                        /
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package single
diff --git a/restlike/single/response.go b/restlike/single/response.go
index edc4833226d0372ae6816f4a190772127aaf6e7e..a0e0314677890b017c093738e1597624fc303b25 100644
--- a/restlike/single/response.go
+++ b/restlike/single/response.go
@@ -1,7 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2022 Privategrity Corporation                                   /
-//                                                                             /
-// All rights reserved.                                                        /
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package single
diff --git a/restlike/single/response_test.go b/restlike/single/response_test.go
index b5e11bf81acca0a91cd9342390b7e712125a4518..da2aedcea8035c8a2189dc0f63fa1a3ed8004256 100644
--- a/restlike/single/response_test.go
+++ b/restlike/single/response_test.go
@@ -1,7 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2022 Privategrity Corporation                                   /
-//                                                                             /
-// All rights reserved.                                                        /
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package single
diff --git a/restlike/single/server.go b/restlike/single/server.go
index 99c2bc08b6327d372ade95711a2a0c945ce33795..607de3e1193f3d99d864cd44b5a675650b1b2ab5 100644
--- a/restlike/single/server.go
+++ b/restlike/single/server.go
@@ -1,7 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2022 Privategrity Corporation                                   /
-//                                                                             /
-// All rights reserved.                                                        /
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package single
diff --git a/restlike/types.go b/restlike/types.go
index 8937575ed720bb14634bf34e6d02908988a28b13..b9158b4a761a318a20701f51e69cad2f57f9af90 100644
--- a/restlike/types.go
+++ b/restlike/types.go
@@ -1,7 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2022 Privategrity Corporation                                   /
-//                                                                             /
-// All rights reserved.                                                        /
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package restlike
diff --git a/restlike/types_test.go b/restlike/types_test.go
index 7b5b1a9d5b1bdaebc556ee4521379e48478019cb..554988050427aeb9f46f75f64f3b17b8c9b316d3 100644
--- a/restlike/types_test.go
+++ b/restlike/types_test.go
@@ -1,7 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2022 Privategrity Corporation                                   /
-//                                                                             /
-// All rights reserved.                                                        /
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package restlike
diff --git a/single/cypher.go b/single/cypher.go
index 6776c0cc673c5d768bf18935ea7c5f66e0ce0de4..ab5c1dce7d6ad0d08e4f5ee8a583f97bdf5b5c2a 100644
--- a/single/cypher.go
+++ b/single/cypher.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package single
 
diff --git a/single/cypher_test.go b/single/cypher_test.go
index 13a47e354db61d1c96f913b6d10a7bf97f029744..113cc7e4c0f807e03317654a796e7dcd63bf0bca 100644
--- a/single/cypher_test.go
+++ b/single/cypher_test.go
@@ -1,8 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package single
diff --git a/single/interfaces.go b/single/interfaces.go
index da28ef80a682b5d6d9ed9a5149972b269892d16b..8a6f965e8728b05b26a09c9f99fe8c248c19cc52 100644
--- a/single/interfaces.go
+++ b/single/interfaces.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package single
 
 import (
@@ -37,7 +44,7 @@ type RequestCmix interface {
 	GetMaxMessageLength() int
 	Send(recipient *id.ID, fingerprint format.Fingerprint,
 		service cMixMsg.Service, payload, mac []byte,
-		cmixParams cmix.CMIXParams) (id.Round, ephemeral.Id, error)
+		cmixParams cmix.CMIXParams) (rounds.Round, ephemeral.Id, error)
 	GetInstance() *network.Instance
 }
 
@@ -65,7 +72,7 @@ type Cmix interface {
 	AddIdentity(id *id.ID, validUntil time.Time, persistent bool)
 	Send(recipient *id.ID, fingerprint format.Fingerprint,
 		service message.Service, payload, mac []byte, cmixParams cmix.CMIXParams) (
-		id.Round, ephemeral.Id, error)
+		rounds.Round, ephemeral.Id, error)
 	AddService(clientID *id.ID, newService message.Service,
 		response message.Processor)
 	DeleteService(clientID *id.ID, toDelete message.Service,
diff --git a/single/listener.go b/single/listener.go
index 01604b1e03839b8ecf23a0fbaa21501122d7d9f8..c13ca7a2a9a92bd0bb4af7e570bd66f3b9f94b1b 100644
--- a/single/listener.go
+++ b/single/listener.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package single
 
 import (
diff --git a/single/listener_test.go b/single/listener_test.go
index b7125f217866dbbefdd9e57757944a828da6f2ab..43006ae979f8a9801921566ebff95ac27ca73fec 100644
--- a/single/listener_test.go
+++ b/single/listener_test.go
@@ -1,8 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package single
@@ -255,7 +255,7 @@ func (m mockListenCmix) GetMaxMessageLength() int {
 
 func (m mockListenCmix) Send(recipient *id.ID, fingerprint format.Fingerprint,
 	service cMixMsg.Service, payload, mac []byte, _ cmix.CMIXParams) (
-	id.Round, ephemeral.Id, error) {
+	rounds.Round, ephemeral.Id, error) {
 	msg := format.NewMessage(m.numPrimeBytes)
 	msg.SetContents(payload)
 	msg.SetMac(mac)
@@ -270,7 +270,7 @@ func (m mockListenCmix) Send(recipient *id.ID, fingerprint format.Fingerprint,
 		p.Process(msg, receptionID.EphemeralIdentity{}, rounds.Round{})
 	}
 
-	return 0, ephemeral.Id{}, nil
+	return rounds.Round{}, ephemeral.Id{}, nil
 }
 
 func (m mockListenCmix) GetInstance() *network.Instance {
diff --git a/single/message/collator.go b/single/message/collator.go
index 9e59eb9e95f00b5b4ec8b0550bf403523e130cec..c5e71cee465960abb7cf87e5d4b73504fc05a475 100644
--- a/single/message/collator.go
+++ b/single/message/collator.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package message
 
 import (
diff --git a/single/message/collator_test.go b/single/message/collator_test.go
index e45d169741e9b510164157cbaee2835ca53157de..cd18eb30eb60f7fb83c7e08cb129fc24905b4a50 100644
--- a/single/message/collator_test.go
+++ b/single/message/collator_test.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package message
 
 import (
diff --git a/single/message/request.go b/single/message/request.go
index f20c36a7fe025bd0ec0a8490a31f4e5bfa38b426..c77689aa8c3e34378f46b816d7c9c3210fbbb939 100644
--- a/single/message/request.go
+++ b/single/message/request.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package message
 
diff --git a/single/message/requestPart.go b/single/message/requestPart.go
index 11d9f27b663cd15d500d7bf3321427c08f70c5d9..fedbed513dad6e220921f9dae34dd18535ebd356 100644
--- a/single/message/requestPart.go
+++ b/single/message/requestPart.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package message
 
diff --git a/single/message/requestPart_test.go b/single/message/requestPart_test.go
index 8f3bbdf8e7cafee33432674fdaad8786dbfad5da..b285af119dd4dd762f90a9692649a097ff9de011 100644
--- a/single/message/requestPart_test.go
+++ b/single/message/requestPart_test.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package message
 
diff --git a/single/message/request_test.go b/single/message/request_test.go
index 3a9120f11883fd19af2630e14cb8a0603a0a2aa0..b0be57400bd9f5bbd204d6ef1aba5d663bf208b9 100644
--- a/single/message/request_test.go
+++ b/single/message/request_test.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package message
 
diff --git a/single/message/responsePart.go b/single/message/responsePart.go
index 02b80cb95fc96f2ab80be204e83ea8bbf0bb233d..03c5154dd904197e1aebcaa3f2bfaba346a41796 100644
--- a/single/message/responsePart.go
+++ b/single/message/responsePart.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package message
 
diff --git a/single/message/responsePart_test.go b/single/message/responsePart_test.go
index 45c06773f113fb64f3e67db2cbeaba4d3bef6bb7..cab9cef67c45c872634d24f8a2bb0da2a1f1e11e 100644
--- a/single/message/responsePart_test.go
+++ b/single/message/responsePart_test.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package message
 
diff --git a/single/params.go b/single/params.go
index 8895818449ba626ea69a112226a8afd182cdc5f3..928938384bc5a24c09d35b9c8a7911a62a65fd21 100644
--- a/single/params.go
+++ b/single/params.go
@@ -1,8 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package single
diff --git a/single/params_test.go b/single/params_test.go
index 7d8224c6127366af542baecb2e755475311967a0..e9c4c49dcd22a2baf482263f97bdf09a2611820f 100644
--- a/single/params_test.go
+++ b/single/params_test.go
@@ -1,8 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package single
diff --git a/single/receivedRequest.go b/single/receivedRequest.go
index b571ef1db60580ecc2f25c47543ce18dff77d226..cc05610088cca70c26539b5df5a0a090616b67cc 100644
--- a/single/receivedRequest.go
+++ b/single/receivedRequest.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package single
 
 import (
@@ -97,11 +104,11 @@ func (r *Request) Respond(payload []byte, cMixParams cmix.CMIXParams,
 
 			jww.DEBUG.Printf("[SU] Sent single-use response cMix message part "+
 				"%d of %d on round %d to %s (eph ID %d) (%s).",
-				i, len(parts), round, r.sender, ephID.Int64(), r.tag)
-			rounds[i] = round
+				i, len(parts), round.ID, r.sender, ephID.Int64(), r.tag)
+			rounds[i] = round.ID
 
 			r.net.GetInstance().GetRoundEvents().AddRoundEventChan(
-				round, sendResults, timeout, states.COMPLETED, states.FAILED)
+				round.ID, sendResults, timeout, states.COMPLETED, states.FAILED)
 		}(i, parts[i].Marshal())
 	}
 
diff --git a/single/receivedRequest_test.go b/single/receivedRequest_test.go
index fc7f64f4fc398a5ad3407690d40a269410e1d8c0..4d5762828038be1ba058cc7e59a4bc1dd8490fca 100644
--- a/single/receivedRequest_test.go
+++ b/single/receivedRequest_test.go
@@ -1,8 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package single
@@ -11,6 +11,7 @@ import (
 	"bytes"
 	"gitlab.com/elixxir/client/cmix"
 	cmixMsg "gitlab.com/elixxir/client/cmix/message"
+	"gitlab.com/elixxir/client/cmix/rounds"
 	"gitlab.com/elixxir/client/single/message"
 	"gitlab.com/elixxir/comms/network"
 	"gitlab.com/elixxir/crypto/cyclic"
@@ -186,14 +187,14 @@ func (m *mockRequestCmix) GetMaxMessageLength() int {
 
 func (m *mockRequestCmix) Send(_ *id.ID, fp format.Fingerprint,
 	_ cmixMsg.Service, payload, mac []byte, _ cmix.CMIXParams) (
-	id.Round, ephemeral.Id, error) {
+	rounds.Round, ephemeral.Id, error) {
 	msg := format.NewMessage(m.numPrimeBytes)
 	msg.SetMac(mac)
 	msg.SetKeyFP(fp)
 	msg.SetContents(payload)
 	m.sendPayload <- msg
 
-	return 0, ephemeral.Id{}, nil
+	return rounds.Round{}, ephemeral.Id{}, nil
 }
 
 func (m *mockRequestCmix) GetInstance() *network.Instance {
diff --git a/single/request.go b/single/request.go
index 08e78c6effd39046fada90042fd04efd8472855a..16429e835021a6eb5b570ba7d60362ae5ba0dca6 100644
--- a/single/request.go
+++ b/single/request.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package single
 
 import (
@@ -204,14 +211,14 @@ func TransmitRequest(recipient contact.Contact, tag string, payload []byte,
 
 	jww.DEBUG.Printf("[SU] Sent single-use request cMix message part "+
 		"%d of %d on round %d to %s (eph ID %d) (%s).",
-		0, len(parts)+1, rid, recipient.ID, ephID.Int64(), tag)
+		0, len(parts)+1, rid.ID, recipient.ID, ephID.Int64(), tag)
 
 	var wg sync.WaitGroup
 	wg.Add(len(parts))
 	failed := uint32(0)
 
 	roundIDs := make([]id.Round, len(parts)+1)
-	roundIDs[0] = rid
+	roundIDs[0] = rid.ID
 	for i, part := range parts {
 		go func(i int, part []byte) {
 			defer wg.Done()
@@ -224,9 +231,7 @@ func TransmitRequest(recipient contact.Contact, tag string, payload []byte,
 			encryptedPayload := auth.Crypt(key, fp[:24], requestPart.Marshal())
 			mac := singleUse.MakeMAC(key, encryptedPayload)
 
-			var ephID ephemeral.Id
-			var err error
-			roundIDs[i], ephID, err = net.Send(recipient.ID, fp,
+			r, ephID, err := net.Send(recipient.ID, fp,
 				cmixMsg.Service{}, encryptedPayload, mac, params.CmixParams)
 			if err != nil {
 				atomic.AddUint32(&failed, 1)
@@ -235,6 +240,7 @@ func TransmitRequest(recipient contact.Contact, tag string, payload []byte,
 					i, len(part)+1, recipient.ID, tag, err)
 				return
 			}
+			roundIDs[i] = r.ID
 
 			jww.DEBUG.Printf("[SU] Sent single-use request cMix message part "+
 				"%d of %d on round %d to %s (eph ID %d) (%s).", i,
@@ -256,7 +262,7 @@ func TransmitRequest(recipient contact.Contact, tag string, payload []byte,
 	remainingTimeout := params.Timeout - netTime.Since(timeStart)
 	go waitForTimeout(timeoutKillChan, wrapper, remainingTimeout)
 
-	return []id.Round{rid}, sendingID, nil
+	return []id.Round{rid.ID}, sendingID, nil
 }
 
 // generateDhKeys generates a new public key and DH key.
diff --git a/single/requestPartProcessor.go b/single/requestPartProcessor.go
index 8649237e539e6892c3e7fcdea9bc13c961b71fa4..34293282ed87f4ab323336ea364db3b169275b90 100644
--- a/single/requestPartProcessor.go
+++ b/single/requestPartProcessor.go
@@ -1,8 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package single
diff --git a/single/request_test.go b/single/request_test.go
index 7e2847324e140fba5e36320c6a22c01650cfac04..4da6d4833e17eb15f2bfa428549739b6cb675bb8 100644
--- a/single/request_test.go
+++ b/single/request_test.go
@@ -1,8 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package single
diff --git a/single/responseProcessor.go b/single/responseProcessor.go
index 942a8443cb32a3b9ea40d357f5e9b3277c59123a..4351900dc228ef09b3deb58e381ab4b920436aa3 100644
--- a/single/responseProcessor.go
+++ b/single/responseProcessor.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package single
 
 import (
diff --git a/single/roundCollector.go b/single/roundCollector.go
index 4d48b8e32c0f3e458457502481dd69344c510ee1..d1f7c5d84f59100ebeb4492e5b51421140690a19 100644
--- a/single/roundCollector.go
+++ b/single/roundCollector.go
@@ -1,8 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package single
diff --git a/single/utils_test.go b/single/utils_test.go
index 66e7f0e6d670bfc0e19e8ef237d4e2277abb43ec..003d68e54cf6ca822918d07ca77985323ea8e70a 100644
--- a/single/utils_test.go
+++ b/single/utils_test.go
@@ -1,8 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package single
@@ -118,7 +118,7 @@ func (m *mockCmix) AddIdentity(*id.ID, time.Time, bool) {}
 
 func (m *mockCmix) Send(recipient *id.ID, fp format.Fingerprint,
 	ms message.Service, payload, mac []byte, _ cmix.CMIXParams) (
-	id.Round, ephemeral.Id, error) {
+	rounds.Round, ephemeral.Id, error) {
 
 	msg := format.NewMessage(m.numPrimeBytes)
 	msg.SetMac(mac)
@@ -155,7 +155,7 @@ func (m *mockCmix) Send(recipient *id.ID, fp format.Fingerprint,
 		})
 	}
 
-	return 0, ephemeral.Id{}, nil
+	return rounds.Round{}, ephemeral.Id{}, nil
 }
 
 func serviceKey(ms message.Service) string {
diff --git a/stoppable/multi.go b/stoppable/multi.go
index 60d1c8530300f2d52babf469d923627f236a6f1d..3ac77c7507fb058af1deac2b098121b16d3569b0 100644
--- a/stoppable/multi.go
+++ b/stoppable/multi.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package stoppable
 
@@ -61,10 +61,13 @@ func (m *Multi) GetStatus() Status {
 	lowestStatus := Stopped
 	m.mux.RLock()
 
-	for _, s := range m.stoppables {
+	for i := range m.stoppables {
+		s := m.stoppables[i]
 		status := s.GetStatus()
 		if status < lowestStatus {
 			lowestStatus = status
+			jww.TRACE.Printf("Stoppable %s has status %s",
+				s.Name(), status.String())
 		}
 	}
 
@@ -73,6 +76,26 @@ func (m *Multi) GetStatus() Status {
 	return lowestStatus
 }
 
+// GetRunningProcesses returns the names of all running processes at the time
+// of this call. Note that this list may change and is subject to race
+// conditions if multiple threads are in the process of starting or stopping.
+func (m *Multi) GetRunningProcesses() []string {
+	m.mux.RLock()
+
+	runningProcesses := make([]string, 0)
+	for i := range m.stoppables {
+		s := m.stoppables[i]
+		status := s.GetStatus()
+		if status < Stopped {
+			runningProcesses = append(runningProcesses, s.Name())
+		}
+	}
+
+	m.mux.RUnlock()
+
+	return runningProcesses
+}
+
 // IsRunning returns true if Stoppable is marked as running.
 func (m *Multi) IsRunning() bool {
 	return m.GetStatus() == Running
@@ -90,7 +113,7 @@ func (m *Multi) IsStopped() bool {
 
 // Close issues a close signal to all child stoppables and marks the status of
 // the Multi Stoppable as stopping. Returns an error if one or more child
-// stoppables failed to close but it does not return their specific errors and
+// stoppables failed to close, but it does not return their specific errors and
 // assumes they print them to the log.
 func (m *Multi) Close() error {
 	var numErrors uint32
diff --git a/stoppable/multi_test.go b/stoppable/multi_test.go
index 4a7eaf0873019d7ab9bd89e4f6aac2ba8f1661c9..af88627451dbd5ce17d19b2f789098d310f6f8bc 100644
--- a/stoppable/multi_test.go
+++ b/stoppable/multi_test.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package stoppable
 
diff --git a/stoppable/single.go b/stoppable/single.go
index dfde7242ed83f0af975efa0656933b56d0b8145a..ea11ab42b586c3c1543509b5f575cda75f0cfca5 100644
--- a/stoppable/single.go
+++ b/stoppable/single.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package stoppable
 
diff --git a/stoppable/single_test.go b/stoppable/single_test.go
index c93a1ebfcc1815b2d5c82e7f2e2dc43ff96a076c..3384396e4c7c80158aeb05ef3de4dc55a2fa720f 100644
--- a/stoppable/single_test.go
+++ b/stoppable/single_test.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package stoppable
 
diff --git a/stoppable/status.go b/stoppable/status.go
index 1b306bd69a13394d8321c52b742ef5ecf82a83a9..089516de1f86fdcd656536b0654eec9bd26c13fd 100644
--- a/stoppable/status.go
+++ b/stoppable/status.go
@@ -1,8 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package stoppable
diff --git a/stoppable/status_test.go b/stoppable/status_test.go
index c2f4bcd05f106e1f0bc6e6083a88096a3cdde1f7..5c44b45870ff1082d3d90125a4a57d9a9339e4e8 100644
--- a/stoppable/status_test.go
+++ b/stoppable/status_test.go
@@ -1,8 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package stoppable
diff --git a/stoppable/stoppable.go b/stoppable/stoppable.go
index b5b072d1424feddf97cd029fa08d519ef2998c01..65df5267197e7ea761ee7d4a7c33b9ead2e16ba3 100644
--- a/stoppable/stoppable.go
+++ b/stoppable/stoppable.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package stoppable
 
diff --git a/stoppable/stoppable_test.go b/stoppable/stoppable_test.go
index 0f070317aedef9fca29a0b66d023b4e7d151517f..1c5098cf2713979f27d24c53ca4385ac8852564d 100644
--- a/stoppable/stoppable_test.go
+++ b/stoppable/stoppable_test.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package stoppable
 
diff --git a/storage/clientVersion/store.go b/storage/clientVersion/store.go
index 5b6e951ef6c0bf5b86049b636606fa015f9d4062..f1ae712d873b3d73004826c231aec0b5fa9fc341 100644
--- a/storage/clientVersion/store.go
+++ b/storage/clientVersion/store.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package clientVersion
 
@@ -113,5 +113,5 @@ func (s *Store) save() error {
 		Data:      []byte(s.version.String()),
 	}
 
-	return s.kv.Set(storeKey, storeVersion, &obj)
+	return s.kv.Set(storeKey, &obj)
 }
diff --git a/storage/clientVersion/store_test.go b/storage/clientVersion/store_test.go
index 0e8cae86f2822b5ea9d3cb09e1bc71cd0c682884..9da1b75ef38491e6405e9c86f9cdf4a77cf48755 100644
--- a/storage/clientVersion/store_test.go
+++ b/storage/clientVersion/store_test.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package clientVersion
 
@@ -71,7 +71,7 @@ func TestLoadStore_ParseVersionError(t *testing.T) {
 		Data:      []byte("invalid version"),
 	}
 
-	err := kv.Prefix(prefix).Set(storeKey, storeVersion, &obj)
+	err := kv.Prefix(prefix).Set(storeKey, &obj)
 	if err != nil {
 		t.Fatalf("Failed to save Store: %+v", err)
 	}
diff --git a/storage/ndf.go b/storage/ndf.go
index 46df6a07161880e15fb75107c692fddaadf45a05..7bac8db591a15c2a76a2428e8ed47f176dfe637f 100644
--- a/storage/ndf.go
+++ b/storage/ndf.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package storage
 
diff --git a/storage/ndf_test.go b/storage/ndf_test.go
index 4d48ab2d28d7330511f8474a9a335ef023505eb6..d628f0a19534b50777390c7f174c4e43c4226a39 100644
--- a/storage/ndf_test.go
+++ b/storage/ndf_test.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package storage
 
diff --git a/storage/regCode.go b/storage/regCode.go
index 2a7d15f34895e0e7d1a7581c18e5a5e50033de7c..83647179c4237d3e09607af6e4bcc89f42181ab3 100644
--- a/storage/regCode.go
+++ b/storage/regCode.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package storage
 
diff --git a/storage/regStatus.go b/storage/regStatus.go
index 90b355e75a3b17cdf90e15f413b816f83d47d279..5ff8cdd4d35a1b9be90a3c07653e62cf07d63dbd 100644
--- a/storage/regStatus.go
+++ b/storage/regStatus.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package storage
 
diff --git a/storage/session.go b/storage/session.go
index d181f07428b1178b83a7b0121c980882c79d1c37..e982415a1ed6523a3ad99d6a4711c6a4a31fe514 100644
--- a/storage/session.go
+++ b/storage/session.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 // Session object definition
 
@@ -195,9 +195,10 @@ func (s *session) Get(key string) (*versioned.Object, error) {
 	return s.kv.Get(key, currentSessionVersion)
 }
 
-// Set a value in the session
+// Set a value in the session. If you wish to maintain versioning,
+// the [versioned.Object]'s Version field must be set.
 func (s *session) Set(key string, object *versioned.Object) error {
-	return s.kv.Set(key, currentSessionVersion, object)
+	return s.kv.Set(key, object)
 }
 
 // Delete a value in the session
diff --git a/storage/session_test.go b/storage/session_test.go
index 27a09e603ab719071a8265e4ae96a03a92517c7a..fd72d302adfc418602a1480245547bb8262a862d 100644
--- a/storage/session_test.go
+++ b/storage/session_test.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package storage
 
diff --git a/storage/user/cryptographic.go b/storage/user/cryptographic.go
index 8c245fc70ac257dc9eef14d9848be007c7831343..54fc60f864c7c602c676a3de38c647777645c895 100644
--- a/storage/user/cryptographic.go
+++ b/storage/user/cryptographic.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package user
 
@@ -216,8 +216,7 @@ func (ci *CryptographicIdentity) save(kv *versioned.KV) error {
 		Data:      enc,
 	}
 
-	return kv.Set(cryptographicIdentityKey,
-		currentCryptographicIdentityVersion, obj)
+	return kv.Set(cryptographicIdentityKey, obj)
 }
 
 func (ci *CryptographicIdentity) GetTransmissionID() *id.ID {
diff --git a/storage/user/cryptographic_test.go b/storage/user/cryptographic_test.go
index 0b9f92d9525600ad66c7746dbda12fa06fc6a318..7fb9f6c3b9e4f3c770db0b7fc6cecc95cb25afcd 100644
--- a/storage/user/cryptographic_test.go
+++ b/storage/user/cryptographic_test.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package user
 
diff --git a/storage/user/info.go b/storage/user/info.go
index fc272cb0fe134b767e399b4bb9fca2a8cd3411e4..a16b4b754a625c386f0dc569f911188b22e742a7 100644
--- a/storage/user/info.go
+++ b/storage/user/info.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package user
 
diff --git a/storage/user/registation.go b/storage/user/registation.go
index 4da19b4cd0faf8e83fe22ad2e177afb8d8109897..aa144ef7f957a54205a95910ff272a82f9a46a36 100644
--- a/storage/user/registation.go
+++ b/storage/user/registation.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package user
 
@@ -95,8 +95,7 @@ func (u *User) SetTransmissionRegistrationValidationSignature(b []byte) {
 		Data:      b,
 	}
 
-	err := u.kv.Set(transmissionRegValidationSigKey,
-		currentRegValidationSigVersion, obj)
+	err := u.kv.Set(transmissionRegValidationSigKey, obj)
 	if err != nil {
 		jww.FATAL.Panicf("Failed to store the transmission Identity Validation "+
 			"Signature: %s", err)
@@ -122,8 +121,7 @@ func (u *User) SetReceptionRegistrationValidationSignature(b []byte) {
 		Data:      b,
 	}
 
-	err := u.kv.Set(receptionRegValidationSigKey,
-		currentRegValidationSigVersion, obj)
+	err := u.kv.Set(receptionRegValidationSigKey, obj)
 	if err != nil {
 		jww.FATAL.Panicf("Failed to store the reception Identity Validation "+
 			"Signature: %s", err)
@@ -148,13 +146,12 @@ func (u *User) SetRegistrationTimestamp(tsNano int64) {
 	binary.BigEndian.PutUint64(tsBytes, uint64(tsNano))
 
 	obj := &versioned.Object{
-		Version:   currentRegValidationSigVersion,
+		Version:   registrationTimestampVersion,
 		Timestamp: netTime.Now(),
 		Data:      tsBytes,
 	}
 
-	err := u.kv.Set(registrationTimestampKey,
-		registrationTimestampVersion, obj)
+	err := u.kv.Set(registrationTimestampKey, obj)
 	if err != nil {
 		jww.FATAL.Panicf("Failed to store the reception timestamp: %s", err)
 	}
diff --git a/storage/user/registation_test.go b/storage/user/registation_test.go
index 346e662758223a755e13c5e19186002ae6b9ec6f..4ada8cf0a9ce106956f36428c416d146853b5dbb 100644
--- a/storage/user/registation_test.go
+++ b/storage/user/registation_test.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package user
 
@@ -137,7 +137,7 @@ func TestUser_loadRegistrationValidationSignature(t *testing.T) {
 
 	sig := []byte("transmissionsignature")
 	err = kv.Set(transmissionRegValidationSigKey,
-		currentRegValidationSigVersion, &versioned.Object{
+		&versioned.Object{
 			Version:   currentRegValidationSigVersion,
 			Timestamp: netTime.Now(),
 			Data:      sig,
@@ -153,7 +153,7 @@ func TestUser_loadRegistrationValidationSignature(t *testing.T) {
 
 	sig = []byte("receptionsignature")
 	err = kv.Set(receptionRegValidationSigKey,
-		currentRegValidationSigVersion, &versioned.Object{
+		&versioned.Object{
 			Version:   currentRegValidationSigVersion,
 			Timestamp: netTime.Now(),
 			Data:      sig,
@@ -252,12 +252,12 @@ func TestUser_loadRegistrationTimestamp(t *testing.T) {
 	data := make([]byte, 8)
 	binary.BigEndian.PutUint64(data, uint64(testTime.UnixNano()))
 	vo := &versioned.Object{
-		Version:   currentRegValidationSigVersion,
+		Version:   registrationTimestampVersion,
 		Timestamp: netTime.Now(),
 		Data:      data,
 	}
-	err = kv.Set(registrationTimestampKey,
-		registrationTimestampVersion, vo)
+
+	err = kv.Set(registrationTimestampKey, vo)
 	if err != nil {
 		t.Errorf("Failed to set reg validation sig key in kv store: %+v", err)
 	}
diff --git a/storage/user/user.go b/storage/user/user.go
index 5b84321a97cc169df474ab2ebd602bfb2769c0b1..b2db39a4e53f3dd15a5d457654b28327a41be613 100644
--- a/storage/user/user.go
+++ b/storage/user/user.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package user
 
diff --git a/storage/user/user_test.go b/storage/user/user_test.go
index 9198e48f607e3c25d79d74242f7607819a83efd1..b55de9534c4eeeaac3369fa6a25d2e3b29a12bcf 100644
--- a/storage/user/user_test.go
+++ b/storage/user/user_test.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package user
 
diff --git a/storage/user/username.go b/storage/user/username.go
index c36e0eba99883f5d735d4aeb2e557848f8ff4180..7a0b939da475473602480d2390ecabcebaefd2c0 100644
--- a/storage/user/username.go
+++ b/storage/user/username.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package user
 
@@ -39,7 +39,7 @@ func (u *User) SetUsername(username string) error {
 		Data:      []byte(username),
 	}
 
-	err := u.kv.Set(usernameKey, currentUsernameVersion, obj)
+	err := u.kv.Set(usernameKey, obj)
 	if err != nil {
 		jww.FATAL.Panicf("Failed to store the username: %s", err)
 	}
diff --git a/storage/user/username_test.go b/storage/user/username_test.go
index a52b20ac003d692c38ba632299354bb8ce698faf..91f8b64a30db6862e98888e7e9dd25ecfcb69404 100644
--- a/storage/user/username_test.go
+++ b/storage/user/username_test.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package user
 
@@ -120,7 +120,7 @@ func TestUser_loadUsername(t *testing.T) {
 
 	u1 := "zezima"
 
-	err = u.kv.Set(usernameKey, currentUsernameVersion, &versioned.Object{
+	err = u.kv.Set(usernameKey, &versioned.Object{
 		Version:   currentUsernameVersion,
 		Timestamp: netTime.Now(),
 		Data:      []byte(u1),
diff --git a/storage/utility/NDF.go b/storage/utility/NDF.go
index e4e6281b26ed92c6466a8afaa9cbec7375ed5107..c01485f26856e0ad111dab4614992045d7d585e4 100644
--- a/storage/utility/NDF.go
+++ b/storage/utility/NDF.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package utility
 
@@ -43,5 +43,5 @@ func SaveNDF(kv *versioned.KV, key string, ndf *ndf.NetworkDefinition) error {
 		Data:      marshaled,
 	}
 
-	return kv.Set(key, currentNDFVersion, &obj)
+	return kv.Set(key, &obj)
 }
diff --git a/storage/utility/blockStore.go b/storage/utility/blockStore.go
index 053e015dd2171e41755afeb6c0e9674d4a2daf78..d81e0fbf363d500d051638c866ade4cbbd777d2f 100644
--- a/storage/utility/blockStore.go
+++ b/storage/utility/blockStore.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package utility
 
 import (
@@ -155,7 +162,7 @@ func (bs *BlockStore) saveBlock() error {
 	}
 
 	// Save to storage
-	err = bs.kv.Set(bs.getKey(bs.lastSaved), blockVersion, &obj)
+	err = bs.kv.Set(bs.getKey(bs.lastSaved), &obj)
 	if err != nil {
 		return errors.Errorf(bKvSaveErr, bs.lastSaved, err)
 	}
@@ -214,7 +221,7 @@ func (bs *BlockStore) save() error {
 	}
 
 	// Save to storage
-	err := bs.kv.Set(blockStoreKey, blockStoreVersion, &obj)
+	err := bs.kv.Set(blockStoreKey, &obj)
 	if err != nil {
 		return errors.Errorf(bsKvSaveErr, err)
 	}
diff --git a/storage/utility/blockStore_test.go b/storage/utility/blockStore_test.go
index 3f13417858d38cb5d7b94667f17c0d17535bf29b..217089bbd0916cf26f3de65468c0ab05dacd20fc 100644
--- a/storage/utility/blockStore_test.go
+++ b/storage/utility/blockStore_test.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package utility
 
 import (
@@ -208,7 +215,7 @@ func TestBlockStore_loadBlock_UnmarshalError(t *testing.T) {
 	}
 
 	// Save to storage
-	err := bs.kv.Set(bs.getKey(bs.lastSaved), blockVersion, &obj)
+	err := bs.kv.Set(bs.getKey(bs.lastSaved), &obj)
 	if err != nil {
 		t.Errorf("Failed to save data to KV: %+v", err)
 	}
@@ -338,7 +345,7 @@ func TestBlockStore_load_UnmarshalError(t *testing.T) {
 	}
 
 	// Save to storage
-	err := kv.Set(blockStoreKey, blockStoreVersion, &obj)
+	err := kv.Set(blockStoreKey, &obj)
 	if err != nil {
 		t.Fatalf("failed to save object to storage: %+v", err)
 	}
diff --git a/storage/utility/bucket.go b/storage/utility/bucket.go
index 46b3da9a9d7733b0ce2abb5812a451ea9ae8e419..fd3061e8f5f311f55a0a7e47648c46fa9114de37 100644
--- a/storage/utility/bucket.go
+++ b/storage/utility/bucket.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package utility
 
@@ -68,7 +68,7 @@ func (s *BucketStore) save(inBucket uint32, timestamp int64) {
 		Data:      data,
 	}
 
-	err = s.kv.Set(bucketStoreKey, bucketStoreVersion, &obj)
+	err = s.kv.Set(bucketStoreKey, &obj)
 
 	if err != nil {
 		jww.ERROR.Printf("Failed to store %s bucket data: %v",
diff --git a/storage/utility/bucketParams.go b/storage/utility/bucketParams.go
index 756666fa353628fabbb5dee9e4077510cf6666a9..90708af650febc99ab6f6e18f7bb58a51a995ba7 100644
--- a/storage/utility/bucketParams.go
+++ b/storage/utility/bucketParams.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package utility
 
@@ -99,7 +99,7 @@ func (s *BucketParamStore) save() error {
 	}
 
 	// Store object into storage
-	return s.kv.Set(bucketParamsKey, bucketParamsVersion, object)
+	return s.kv.Set(bucketParamsKey, object)
 }
 
 // load extracts the bucket params from store and loads it into the
diff --git a/storage/utility/bucketParams_test.go b/storage/utility/bucketParams_test.go
index d908ac99ad964b35a345fbfde6af92c642b072c4..dc961eb5f2ff719ad2580fef95e53f0319f1802d 100644
--- a/storage/utility/bucketParams_test.go
+++ b/storage/utility/bucketParams_test.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package utility
 
diff --git a/storage/utility/contact.go b/storage/utility/contact.go
index 2050efd8a2664a41bb34c557c807f73d94879a57..98268e686b51cd30f54ad017682f542998ebc8a1 100644
--- a/storage/utility/contact.go
+++ b/storage/utility/contact.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package utility
 
@@ -35,7 +35,7 @@ func StoreContact(kv *versioned.KV, c contact.Contact) error {
 		Data:      c.Marshal(),
 	}
 
-	return kv.Set(makeContactKey(c.ID), currentContactVersion, &obj)
+	return kv.Set(makeContactKey(c.ID), &obj)
 }
 
 // LoadContact reads a contact from a versioned.KV vie their contact ID.
diff --git a/storage/utility/dh.go b/storage/utility/dh.go
index 6295e446d3563127c4c1262733eb3abf8ac8b91e..de697130ae7bf68f41dc88567346992cc181d164 100644
--- a/storage/utility/dh.go
+++ b/storage/utility/dh.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package utility
 
@@ -29,7 +29,7 @@ func StoreCyclicKey(kv *versioned.KV, cy *cyclic.Int, key string) error {
 		Data:      data,
 	}
 
-	return kv.Set(key, currentCyclicVersion, &obj)
+	return kv.Set(key, &obj)
 }
 
 func LoadCyclicKey(kv *versioned.KV, key string) (*cyclic.Int, error) {
diff --git a/storage/utility/dh_test.go b/storage/utility/dh_test.go
index bea2f2448d14a80c3319871f78edf7f1edad90e9..4f25a4768c1dd3e1fa1ed7bc0e52f010ad0e936e 100644
--- a/storage/utility/dh_test.go
+++ b/storage/utility/dh_test.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package utility
 
diff --git a/storage/utility/group.go b/storage/utility/group.go
index 531a31ae4beb24a31cc1aa1ee4d13889e32436b3..769e0fc0fa682e1dafac61fe24fe69c6f16bd930 100644
--- a/storage/utility/group.go
+++ b/storage/utility/group.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package utility
 
@@ -29,7 +29,7 @@ func StoreGroup(kv *versioned.KV, grp *cyclic.Group, key string) error {
 		Data:      data,
 	}
 
-	return kv.Set(key, currentGroupVersion, &obj)
+	return kv.Set(key, &obj)
 }
 
 func LoadGroup(kv *versioned.KV, key string) (*cyclic.Group, error) {
diff --git a/storage/utility/group_test.go b/storage/utility/group_test.go
index 02e6504be687d1e7b331ad63d6c139d9d6963f22..09542e392ed40bb426d055da7c6af2854077fb28 100644
--- a/storage/utility/group_test.go
+++ b/storage/utility/group_test.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package utility
 
diff --git a/storage/utility/id.go b/storage/utility/id.go
index 08472b53e36da3d4912886ca3b19931d0120f78d..6046627b374ebd6f9093452c72cc0cade334cfe5 100644
--- a/storage/utility/id.go
+++ b/storage/utility/id.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package utility
 
 import (
@@ -22,7 +29,7 @@ func StoreID(kv *versioned.KV, sid *id.ID, key string) error {
 		Data:      data,
 	}
 
-	return kv.Set(key, currentIDVersion, &obj)
+	return kv.Set(key, &obj)
 }
 
 func LoadID(kv *versioned.KV, key string) (*id.ID, error) {
diff --git a/storage/utility/knownRounds.go b/storage/utility/knownRounds.go
index 0f8057ce6a21be2023a4b6bff4198e157acfcc3e..d75d094c1e99e7e73781abf3eae89e799a30d8d1 100644
--- a/storage/utility/knownRounds.go
+++ b/storage/utility/knownRounds.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package utility
 
diff --git a/storage/utility/knownRounds_test.go b/storage/utility/knownRounds_test.go
index e7a3a25f8ec33b7d11886b457863e90f48819109..c5e9a565bdcafdd6c728cf3b0186cc4432760674 100644
--- a/storage/utility/knownRounds_test.go
+++ b/storage/utility/knownRounds_test.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package utility
 
diff --git a/storage/utility/messageBuffer.go b/storage/utility/messageBuffer.go
index 4e5a5d32fb1f6695965cd97d1d28a64512eb0ba0..15c3296673f17bcf7a08869e6fef305dc5219031 100644
--- a/storage/utility/messageBuffer.go
+++ b/storage/utility/messageBuffer.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package utility
 
@@ -146,7 +146,7 @@ func (mb *MessageBuffer) save() error {
 	}
 
 	// Save versioned object
-	return mb.kv.Set(mb.key, CurrentMessageBufferVersion, &obj)
+	return mb.kv.Set(mb.key, &obj)
 }
 
 // getMessageList returns a list of all message hashes stored in messages and
diff --git a/storage/utility/messageBuffer_test.go b/storage/utility/messageBuffer_test.go
index fc7f39a7c8fba2acdb6f8eb2efe395afcc7ce814..065c1d6cf099996b4638a88dc7eda180a3bb625c 100644
--- a/storage/utility/messageBuffer_test.go
+++ b/storage/utility/messageBuffer_test.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package utility
 
diff --git a/storage/utility/multiStateVector.go b/storage/utility/multiStateVector.go
index caeeb347f0593852be4ea3bcbdc4c0c2fb558ced..e12b6caff9fbbc262ee679df1399960495fdbffa 100644
--- a/storage/utility/multiStateVector.go
+++ b/storage/utility/multiStateVector.go
@@ -1,8 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package utility
@@ -502,7 +502,7 @@ func (msv *MultiStateVector) save() error {
 		Data:      data,
 	}
 
-	return msv.kv.Set(msv.key, multiStateVectorVersion, obj)
+	return msv.kv.Set(msv.key, obj)
 }
 
 // Delete removes the MultiStateVector from storage.
diff --git a/storage/utility/multiStateVector_test.go b/storage/utility/multiStateVector_test.go
index 38085804b5bf11adbf35e21d240863b84b2a2a0c..e198da67087e19b070dcc235a407d5b97345a607 100644
--- a/storage/utility/multiStateVector_test.go
+++ b/storage/utility/multiStateVector_test.go
@@ -1,8 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package utility
@@ -890,7 +890,7 @@ func TestLoadMultiStateVector_UnmarshalError(t *testing.T) {
 	expectedErr := strings.Split(loadUnmarshalMsvErr, "%")[0]
 
 	// Save invalid data to storage
-	err := kv.Set(makeMultiStateVectorKey(key), multiStateVectorVersion,
+	err := kv.Set(makeMultiStateVectorKey(key),
 		&versioned.Object{
 			Version:   multiStateVectorVersion,
 			Timestamp: netTime.Now(),
diff --git a/storage/utility/sidh.go b/storage/utility/sidh.go
index d8082d872944fa2a24e9f04142e53aff8944f0e7..03599f79dd58d1daef38f3a062c7541b932b8477 100644
--- a/storage/utility/sidh.go
+++ b/storage/utility/sidh.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package utility
 
@@ -93,7 +93,7 @@ func StoreSIDHPublicKey(kv *versioned.KV, sidH *sidh.PublicKey, key string) erro
 		Data:      sidHBytes,
 	}
 
-	return kv.Set(key, currentSIDHPubKeyVersion, &obj)
+	return kv.Set(key, &obj)
 }
 
 // LoadSIDHPubKeyA loads a public key from storage.
@@ -138,7 +138,7 @@ func StoreSIDHPrivateKey(kv *versioned.KV, sidH *sidh.PrivateKey, key string) er
 		Data:      sidHBytes,
 	}
 
-	return kv.Set(key, currentSIDHPrivKeyVersion, &obj)
+	return kv.Set(key, &obj)
 }
 
 // LoadSIDHPrivateKeyA loads a public key from storage.
diff --git a/storage/utility/sidh_test.go b/storage/utility/sidh_test.go
index d547011d3ef6860e685204ce013dd437675215e5..b20b1310aeea6fe3c3b3eeb16d3259bb748a43cc 100644
--- a/storage/utility/sidh_test.go
+++ b/storage/utility/sidh_test.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package utility
 
diff --git a/storage/utility/stateVector.go b/storage/utility/stateVector.go
index 2ed89e2faef5fe3ebcc591e0ca0c933bcd71faf3..f3ed4da6d4612365ea5b564ef5742976a1368626 100644
--- a/storage/utility/stateVector.go
+++ b/storage/utility/stateVector.go
@@ -1,8 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package utility
@@ -388,7 +388,7 @@ func (sv *StateVector) save() error {
 		Data:      data,
 	}
 
-	return sv.kv.Set(sv.key, currentStateVectorVersion, &obj)
+	return sv.kv.Set(sv.key, &obj)
 }
 
 // Delete remove the StateVector from storage.
diff --git a/storage/utility/stateVector_test.go b/storage/utility/stateVector_test.go
index 4b2188b25c6dd41689aea9cbe003ea0ba8443b7a..586f31dc3492f06a56198c683c4a624140e6d220 100644
--- a/storage/utility/stateVector_test.go
+++ b/storage/utility/stateVector_test.go
@@ -1,8 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package utility
@@ -563,7 +563,7 @@ func TestLoadStateVector_GetError(t *testing.T) {
 	expectedErr := "object not found"
 
 	_, err := LoadStateVector(kv, key)
-	if err == nil || err.Error() != expectedErr {
+	if err == nil || kv.Exists(err) {
 		t.Fatalf("LoadStateVector did not return the expected error when no "+
 			"object exists in storage.\nexpected: %s\nreceived: %+v",
 			expectedErr, err)
@@ -582,7 +582,7 @@ func TestLoadStateVector_UnmarshalError(t *testing.T) {
 		Timestamp: netTime.Now(),
 		Data:      []byte("invalidStateVector"),
 	}
-	err := kv.Set(makeStateVectorKey(key), currentStateVectorVersion, &obj)
+	err := kv.Set(makeStateVectorKey(key), &obj)
 	if err != nil {
 		t.Errorf("Failed to save invalid StateVector to storage: %+v", err)
 	}
diff --git a/storage/utils_test.go b/storage/utils_test.go
index 6e9cc93343c47ea97587b76bb0951bc9e3e8ac94..fbabefb2e1325b6673f72feac256089704289732 100644
--- a/storage/utils_test.go
+++ b/storage/utils_test.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package storage
 
 import (
diff --git a/storage/versioned/kv.go b/storage/versioned/kv.go
index 2b8b7ae2129d5a67fdf576297a4318e229c91ff8..4b0179fa3e8cc764263a3d6f305bfafa6a5e9522 100644
--- a/storage/versioned/kv.go
+++ b/storage/versioned/kv.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package versioned
 
@@ -131,8 +131,10 @@ func (v *KV) Delete(key string, version uint64) error {
 // Set upserts new data into the storage
 // When calling this, you are responsible for prefixing the key with the correct
 // type optionally unique id! Call MakeKeyWithPrefix() to do so.
-func (v *KV) Set(key string, version uint64, object *Object) error {
-	key = v.makeKey(key, version)
+// The [Object] should contain the versioning if you are maintaining such
+// a functionality.
+func (v *KV) Set(key string, object *Object) error {
+	key = v.makeKey(key, object.Version)
 	jww.TRACE.Printf("Set %p with key %v", v.r.data, key)
 	return v.r.data.Set(key, object)
 }
@@ -164,3 +166,9 @@ func (v *KV) GetFullKey(key string, version uint64) string {
 func (v *KV) makeKey(key string, version uint64) string {
 	return fmt.Sprintf("%s%s_%d", v.prefix, key, version)
 }
+
+// Exists returns false if the error indicates the element doesn't
+// exist.
+func (v *KV) Exists(err error) bool {
+	return ekv.Exists(err)
+}
diff --git a/storage/versioned/kv_test.go b/storage/versioned/kv_test.go
index cd34474ed2fe18942286a88db17ccce3f71295c1..deb7eacf20a7d67dd274ee6e59337a6cb9610fb4 100644
--- a/storage/versioned/kv_test.go
+++ b/storage/versioned/kv_test.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package versioned
 
@@ -188,7 +188,7 @@ func TestVersionedKV_Set(t *testing.T) {
 		Timestamp: netTime.Now(),
 		Data:      []byte("not upgraded"),
 	}
-	err := vkv.Set("test", originalVersion, &original)
+	err := vkv.Set("test", &original)
 	if err != nil {
 		t.Fatal(err)
 	}
diff --git a/storage/versioned/object.go b/storage/versioned/object.go
index 8cdec88c27c59dc99284089996fbcd2e2c6394a0..bd7d43730571aa743a907f6419dcdca7b0d9f2f5 100644
--- a/storage/versioned/object.go
+++ b/storage/versioned/object.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package versioned
 
diff --git a/storage/versioned/object_test.go b/storage/versioned/object_test.go
index 4ba12575a327269b2094ff7c73d90fa2a7873f2c..94ac4ec41123609591ff84fc2195d660653e4da4 100644
--- a/storage/versioned/object_test.go
+++ b/storage/versioned/object_test.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package versioned
 
diff --git a/ud/addFact.go b/ud/addFact.go
index 719e7d137ab1f9c3e5ce4d414c9db08876d668a4..069a4f4251800b92d12751a45cdaa24dbd73008b 100644
--- a/ud/addFact.go
+++ b/ud/addFact.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package ud
 
 import (
@@ -40,7 +47,7 @@ func (m *Manager) addFact(inFact fact.Fact, myId *id.ID,
 	fHash := factID.Fingerprint(f)
 
 	// Sign our inFact for putting into the request
-	privKey, err := m.user.GetReceptionIdentity().GetRSAPrivatePem()
+	privKey, err := m.user.GetReceptionIdentity().GetRSAPrivateKey()
 	if err != nil {
 		return "", err
 	}
diff --git a/ud/addFact_test.go b/ud/addFact_test.go
index 1a1a38cdcd75f6b416786f76742bfe92ca990d64..7f5bc06f5e2b63f056a86b7d1e120b4d50860a90 100644
--- a/ud/addFact_test.go
+++ b/ud/addFact_test.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package ud
 
 import (
diff --git a/ud/channelIDTracking.go b/ud/channelIDTracking.go
new file mode 100644
index 0000000000000000000000000000000000000000..e40f4a1e33cbfb5519f7f0bc4964df04c9cd01b8
--- /dev/null
+++ b/ud/channelIDTracking.go
@@ -0,0 +1,380 @@
+package ud
+
+import (
+	"crypto/ed25519"
+	"encoding/json"
+	"errors"
+	"gitlab.com/xx_network/primitives/netTime"
+	"sync"
+	"time"
+
+	jww "github.com/spf13/jwalterweatherman"
+
+	"gitlab.com/elixxir/client/channels"
+	"gitlab.com/elixxir/client/stoppable"
+	"gitlab.com/elixxir/client/storage/versioned"
+	"gitlab.com/elixxir/client/xxdk"
+	"gitlab.com/elixxir/comms/mixmessages"
+	"gitlab.com/elixxir/crypto/channel"
+	"gitlab.com/elixxir/crypto/fastRNG"
+	"gitlab.com/xx_network/comms/connect"
+)
+
+const (
+	registrationDiskKey     = "registrationDiskKey"
+	registrationDiskVersion = 0
+	graceDuration           = time.Hour
+)
+
+var ErrChannelLeaseSignature = errors.New("failure to validate lease signature")
+
+// loadRegistrationDisk loads a registrationDisk from the kv
+// and returns the registrationDisk.
+func loadRegistrationDisk(kv *versioned.KV) (registrationDisk, error) {
+	obj, err := kv.Get(registrationDiskKey, registrationDiskVersion)
+	if err != nil {
+		return registrationDisk{}, err
+	}
+	return UnmarshallRegistrationDisk(obj.Data)
+}
+
+// saveRegistrationDisk saves the given saveRegistrationDisk to
+// the given kv.
+func saveRegistrationDisk(kv *versioned.KV, reg registrationDisk) error {
+	regBytes, err := reg.Marshall()
+	if err != nil {
+		return err
+	}
+	obj := versioned.Object{
+		Version:   registrationDiskVersion,
+		Timestamp: netTime.Now(),
+		Data:      regBytes,
+	}
+	return kv.Set(registrationDiskKey, &obj)
+}
+
+// registrationDisk is used to encapsulate the channel user's key pair,
+// lease and lease signature.
+type registrationDisk struct {
+	rwmutex sync.RWMutex
+
+	Registered bool
+	PublicKey  ed25519.PublicKey
+	PrivateKey ed25519.PrivateKey
+	Lease      int64
+	Signature  []byte
+}
+
+// newRegistrationDisk creates a new newRegistrationDisk.
+func newRegistrationDisk(publicKey ed25519.PublicKey, privateKey ed25519.PrivateKey,
+	lease time.Time, signature []byte) registrationDisk {
+	return registrationDisk{
+		Lease:      lease.UnixNano(),
+		PublicKey:  publicKey,
+		PrivateKey: privateKey,
+		Signature:  signature,
+	}
+}
+
+func (r registrationDisk) IsRegistered() bool {
+	r.rwmutex.RLock()
+	defer r.rwmutex.RUnlock()
+
+	return r.Registered
+}
+
+// Update updates the registrationDisk that is currently
+// stored on the kv with a new lease and lease signature.
+func (r registrationDisk) Update(lease int64, signature []byte) {
+	r.rwmutex.Lock()
+	defer r.rwmutex.Unlock()
+
+	r.Registered = true
+	r.Lease = lease
+	r.Signature = signature
+}
+
+// Marshall marshalls the registrationDisk.
+func (r registrationDisk) Marshall() ([]byte, error) {
+	r.rwmutex.RLock()
+	defer r.rwmutex.RUnlock()
+
+	return json.Marshal(&r)
+}
+
+// UnmarshallRegistrationDisk unmarshalls a registrationDisk
+func UnmarshallRegistrationDisk(data []byte) (registrationDisk, error) {
+	var r registrationDisk
+	err := json.Unmarshal(data, &r)
+	if err != nil {
+		return registrationDisk{}, err
+	}
+	return r, nil
+}
+
+// GetLease returns the current registrationDisk lease.
+func (r registrationDisk) GetLease() time.Time {
+	r.rwmutex.RLock()
+	defer r.rwmutex.RUnlock()
+
+	return time.Unix(0, r.Lease)
+}
+
+// GetPublicKey returns the current public key.
+func (r registrationDisk) GetPublicKey() ed25519.PublicKey {
+	r.rwmutex.RLock()
+	defer r.rwmutex.RUnlock()
+
+	pubkey := make([]byte, ed25519.PublicKeySize)
+	copy(pubkey, r.PublicKey)
+	return pubkey
+}
+
+// GetPrivateKey returns the current private key.
+func (r registrationDisk) getPrivateKey() ed25519.PrivateKey {
+	r.rwmutex.RLock()
+	defer r.rwmutex.RUnlock()
+
+	return r.PrivateKey
+}
+
+// GetLeaseSignature returns the currentl signature and lease time.
+func (r registrationDisk) GetLeaseSignature() ([]byte, time.Time) {
+	r.rwmutex.RLock()
+	defer r.rwmutex.RUnlock()
+
+	return r.Signature, time.Unix(0, r.Lease)
+}
+
+// clientIDTracker encapsulates the client channel lease and the
+// repetitive scheduling of new lease registrations when the
+// current lease expires.
+type clientIDTracker struct {
+	kv *versioned.KV
+
+	username string
+
+	registrationDisk  *registrationDisk
+	receptionIdentity *xxdk.ReceptionIdentity
+
+	rngSource *fastRNG.StreamGenerator
+
+	host     *connect.Host
+	comms    channelLeaseComms
+	udPubKey ed25519.PublicKey
+}
+
+// clientIDTracker implements the NameService interface.
+var _ channels.NameService = (*clientIDTracker)(nil)
+
+// newclientIDTracker creates a new clientIDTracker.
+func newclientIDTracker(comms channelLeaseComms, host *connect.Host, username string, kv *versioned.KV,
+	receptionIdentity xxdk.ReceptionIdentity, udPubKey ed25519.PublicKey, rngSource *fastRNG.StreamGenerator) *clientIDTracker {
+
+	reg, err := loadRegistrationDisk(kv)
+	if !kv.Exists(err) {
+		rng := rngSource.GetStream()
+		defer rng.Close()
+
+		publicKey, privateKey, err := ed25519.GenerateKey(rng)
+		if err != nil {
+			jww.FATAL.Panic(err)
+		}
+
+		reg = registrationDisk{
+			PublicKey:  publicKey,
+			PrivateKey: privateKey,
+			Lease:      0,
+		}
+		err = saveRegistrationDisk(kv, reg)
+		if err != nil {
+			jww.FATAL.Panic(err)
+		}
+	} else if err != nil {
+		jww.FATAL.Panic(err)
+	}
+
+	c := &clientIDTracker{
+		kv:                kv,
+		rngSource:         rngSource,
+		registrationDisk:  &reg,
+		receptionIdentity: &receptionIdentity,
+		username:          username,
+		comms:             comms,
+		host:              host,
+		udPubKey:          udPubKey,
+	}
+
+	if !reg.IsRegistered() {
+		err = c.register()
+		if err != nil {
+			jww.FATAL.Panic(err)
+		}
+	}
+
+	return c
+}
+
+// Start starts the registration worker.
+func (c *clientIDTracker) Start() (stoppable.Stoppable, error) {
+	stopper := stoppable.NewSingle("ud.ClientIDTracker")
+	go c.registrationWorker(stopper)
+	return stopper, nil
+}
+
+func pow(base, exponent int) int {
+	if exponent == 0 {
+		return 1
+	}
+	result := base
+	for i := 2; i <= exponent; i++ {
+		result *= base
+	}
+	return result
+}
+
+// registrationWorker is meant to run in it's own goroutine
+// periodically registering, getting a new lease.
+func (c *clientIDTracker) registrationWorker(stopper *stoppable.Single) {
+	// start backoff at 32 seconds
+	base := 2
+	exponent := 5
+	waitTime := time.Second
+	maxBackoff := 300
+	for {
+		if netTime.Now().After(c.registrationDisk.GetLease().Add(-graceDuration)) {
+			err := c.register()
+			if err != nil {
+				backoffSeconds := pow(base, exponent)
+				if backoffSeconds > maxBackoff {
+					backoffSeconds = maxBackoff
+				} else {
+					exponent += 1
+				}
+				waitTime = time.Second * time.Duration(backoffSeconds)
+			} else {
+				waitTime = time.Second
+			}
+		}
+
+		select {
+		case <-stopper.Quit():
+			return
+		case <-time.After(c.registrationDisk.GetLease().Add(-graceDuration).Sub(netTime.Now())):
+		}
+
+		// Avoid spamming the server in the event that it's service is down.
+		select {
+		case <-stopper.Quit():
+			return
+		case <-time.After(waitTime):
+		}
+	}
+}
+
+// GetUsername returns the username.
+func (c *clientIDTracker) GetUsername() string {
+	return c.username
+}
+
+// GetChannelValidationSignature returns the validation
+// signature and the time it was signed.
+func (c *clientIDTracker) GetChannelValidationSignature() ([]byte, time.Time) {
+	return c.registrationDisk.GetLeaseSignature()
+}
+
+// GetChannelPubkey returns the user's public key.
+func (c *clientIDTracker) GetChannelPubkey() ed25519.PublicKey {
+	return c.registrationDisk.GetPublicKey()
+}
+
+// SignChannelMessage returns the signature of the given
+// message. The ed25519 private key stored in the registrationDisk on the
+// kv is used for signing.
+func (c *clientIDTracker) SignChannelMessage(message []byte) ([]byte, error) {
+	privateKey := c.registrationDisk.getPrivateKey()
+	return ed25519.Sign(privateKey, message), nil
+}
+
+// ValidateoChannelMessage
+func (c *clientIDTracker) ValidateChannelMessage(username string, lease time.Time, pubKey ed25519.PublicKey, authorIDSignature []byte) bool {
+	return channel.VerifyChannelLease(authorIDSignature, pubKey, username, lease, c.udPubKey)
+}
+
+// register causes a request for a new channel lease to be sent to
+// the user discovery server. If successful in procuration of a new lease
+// then it is written to the registrationDisk on the kv.
+func (c *clientIDTracker) register() error {
+	lease, signature, err := c.requestChannelLease()
+	if err != nil {
+		return err
+	}
+
+	c.registrationDisk.Update(lease, signature)
+
+	return nil
+}
+
+// requestChannelLease requests a new channel lease
+// from the user discovery server.
+func (c *clientIDTracker) requestChannelLease() (int64, []byte, error) {
+	ts := netTime.Now().UnixNano()
+	privKey, err := c.receptionIdentity.GetRSAPrivateKey()
+	if err != nil {
+		return 0, nil, err
+	}
+
+	rng := c.rngSource.GetStream()
+	userPubKey := c.registrationDisk.GetPublicKey()
+	fSig, err := channel.SignChannelIdentityRequest(userPubKey, time.Unix(0, ts), privKey, rng)
+	if err != nil {
+		return 0, nil, err
+	}
+	rng.Close()
+
+	msg := &mixmessages.ChannelLeaseRequest{
+		UserID:                 c.receptionIdentity.ID.Marshal(),
+		UserEd25519PubKey:      userPubKey,
+		Timestamp:              ts,
+		UserPubKeyRSASignature: fSig,
+	}
+
+	resp, err := c.comms.SendChannelLeaseRequest(c.host, msg)
+	if err != nil {
+		return 0, nil, err
+	}
+
+	ok := channel.VerifyChannelLease(resp.UDLeaseEd25519Signature,
+		userPubKey, c.username, time.Unix(0, resp.Lease), c.udPubKey)
+	if !ok {
+		return 0, nil, ErrChannelLeaseSignature
+	}
+
+	return resp.Lease, resp.UDLeaseEd25519Signature, err
+}
+
+// StartChannelNameService creates a new clientIDTracker
+// and returns a reference to it's type as the NameService interface.
+// However, it's scheduler thread isn't started until it's Start
+// method is called.
+func (m *Manager) StartChannelNameService() (channels.NameService, error) {
+
+	if m.nameService == nil {
+		udPubKeyBytes := m.user.GetCmix().GetInstance().GetPartialNdf().Get().UDB.DhPubKey
+		username, err := m.store.GetUsername()
+		if err != nil {
+			return nil, err
+		}
+		m.nameService = newclientIDTracker(
+			m.comms,
+			m.ud.host,
+			username,
+			m.getKv(),
+			m.user.GetReceptionIdentity(),
+			udPubKeyBytes,
+			m.getRng())
+
+	}
+
+	return m.nameService, nil
+}
diff --git a/ud/channelIDTracking_test.go b/ud/channelIDTracking_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..52c4c9826949856a363f04c315a2fd5dc7449637
--- /dev/null
+++ b/ud/channelIDTracking_test.go
@@ -0,0 +1,137 @@
+package ud
+
+import (
+	"crypto/ed25519"
+	"crypto/rand"
+	"testing"
+	"time"
+
+	"github.com/stretchr/testify/require"
+
+	"gitlab.com/xx_network/comms/connect"
+	"gitlab.com/xx_network/crypto/csprng"
+	"gitlab.com/xx_network/crypto/signature/rsa"
+	"gitlab.com/xx_network/primitives/id"
+
+	"gitlab.com/elixxir/client/event"
+	"gitlab.com/elixxir/client/storage/versioned"
+	store "gitlab.com/elixxir/client/ud/store"
+	"gitlab.com/elixxir/crypto/fastRNG"
+	"gitlab.com/elixxir/ekv"
+)
+
+func TestSignChannelMessage(t *testing.T) {
+	publicKey, privateKey, err := ed25519.GenerateKey(rand.Reader)
+	require.NoError(t, err)
+
+	reg := registrationDisk{
+		PublicKey:  publicKey,
+		PrivateKey: privateKey,
+		Lease:      0,
+	}
+	c := &clientIDTracker{
+		registrationDisk: &reg,
+	}
+
+	message := []byte("hello world")
+	sig, err := c.SignChannelMessage(message)
+	require.NoError(t, err)
+
+	require.True(t, ed25519.Verify(publicKey, message, sig))
+}
+
+func TestNewRegistrationDisk(t *testing.T) {
+	publicKey, privateKey, err := ed25519.GenerateKey(rand.Reader)
+	require.NoError(t, err)
+	lease := time.Now().UnixNano()
+
+	signature := make([]byte, 64)
+	reg := newRegistrationDisk(publicKey, privateKey, time.Unix(0, lease), signature)
+	require.Equal(t, reg.PublicKey, publicKey)
+	require.Equal(t, reg.PrivateKey, privateKey)
+	require.Equal(t, reg.Signature, signature)
+	require.Equal(t, reg.Lease, lease)
+}
+
+func TestLoadSaveRegistration(t *testing.T) {
+	publicKey, privateKey, err := ed25519.GenerateKey(rand.Reader)
+	require.NoError(t, err)
+	lease := time.Now()
+	signature := make([]byte, 64)
+	reg := newRegistrationDisk(publicKey, privateKey, lease, signature)
+
+	kv := versioned.NewKV(ekv.MakeMemstore())
+
+	registrationDisk, err := loadRegistrationDisk(kv)
+	require.Error(t, err)
+	require.False(t, kv.Exists(err))
+
+	err = saveRegistrationDisk(kv, reg)
+	require.NoError(t, err)
+
+	registrationDisk, err = loadRegistrationDisk(kv)
+	require.NoError(t, err)
+	require.Equal(t, registrationDisk, reg)
+}
+
+func TestChannelIDTracking(t *testing.T) {
+	rngGen := fastRNG.NewStreamGenerator(1000, 10, csprng.NewSystemRNG)
+
+	// comms AddHost
+	stream := rngGen.GetStream()
+	privKey, err := rsa.GenerateKey(stream, 1024)
+	require.NoError(t, err)
+
+	tnm := newTestNetworkManager(t)
+	managerkv := versioned.NewKV(ekv.MakeMemstore())
+	udStore, err := store.NewOrLoadStore(managerkv)
+	m := &Manager{
+		user: mockE2e{
+			grp:     getGroup(),
+			events:  event.NewEventManager(),
+			rng:     rngGen,
+			kv:      managerkv,
+			network: tnm,
+			t:       t,
+			key:     privKey,
+		},
+		store: udStore,
+		comms: &mockComms{},
+	}
+
+	netDef := m.getCmix().GetInstance().GetPartialNdf().Get()
+	udID, err := id.Unmarshal(netDef.UDB.ID)
+	require.NoError(t, err)
+
+	params := connect.GetDefaultHostParams()
+	params.AuthEnabled = false
+	params.SendTimeout = 20 * time.Second
+
+	host, err := m.comms.AddHost(udID, netDef.UDB.Address,
+		[]byte(netDef.UDB.Cert), params)
+	require.NoError(t, err)
+
+	// register
+
+	kv := versioned.NewKV(ekv.MakeMemstore())
+	comms := new(mockComms)
+	username := "Alice"
+
+	udPubKey, udPrivKey, err := ed25519.GenerateKey(rand.Reader)
+	require.NoError(t, err)
+
+	rsaPrivKey, err := m.user.GetReceptionIdentity().GetRSAPrivateKey()
+	require.NoError(t, err)
+
+	comms.SetUserRSAPubKey(rsaPrivKey.GetPublic())
+	comms.SetUDEd25519PrivateKey(&udPrivKey)
+	comms.SetUsername(username)
+
+	myTestClientIDTracker := newclientIDTracker(
+		comms, host, username,
+		kv, m.user.GetReceptionIdentity(),
+		udPubKey, rngGen)
+
+	err = myTestClientIDTracker.register()
+	require.NoError(t, err)
+}
diff --git a/ud/comms.go b/ud/comms.go
index 07a450a405a98750fb6a2bd9dd3424c5c6f5e478..df993f608cc1ccc08a5f3e670a8322e4d97ff819 100644
--- a/ud/comms.go
+++ b/ud/comms.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package ud
 
 import (
@@ -37,6 +44,8 @@ type Comms interface {
 	// object. This will be used to send to the UD service on the above
 	// gRPC send functions.
 	GetHost(hostId *id.ID) (*connect.Host, bool)
+
+	channelLeaseComms
 }
 
 // removeFactComms is a sub-interface of the Comms interface for the
@@ -68,3 +77,7 @@ type registerUserComms interface {
 type addFactComms interface {
 	SendRegisterFact(host *connect.Host, message *pb.FactRegisterRequest) (*pb.FactRegisterResponse, error)
 }
+
+type channelLeaseComms interface {
+	SendChannelLeaseRequest(host *connect.Host, message *pb.ChannelLeaseRequest) (*pb.ChannelLeaseResponse, error)
+}
diff --git a/ud/compileProtobuf.sh b/ud/compileProtobuf.sh
new file mode 100644
index 0000000000000000000000000000000000000000..ff4554cda302477db4d22715d3975d97f80268ac
--- /dev/null
+++ b/ud/compileProtobuf.sh
@@ -0,0 +1,14 @@
+#!/bin/bash
+################################################################################
+## Copyright © 2022 xx foundation                                             ##
+##                                                                            ##
+## Use of this source code is governed by a license that can be found in the  ##
+## LICENSE file.                                                              ##
+################################################################################
+
+# This script will compile the Protobuf file to a Go file (pb.go).
+# This is meant to be called from the top level of the repo.
+
+cd ./ud/ || return
+
+protoc --go_out=. --go_opt=paths=source_relative ./udMessages.proto
diff --git a/ud/confirmFact.go b/ud/confirmFact.go
index a55da37566945a03b5c0a276f92b7e30ec220f4d..8fdafc24af9a52ac4b664e56dfe99aec3e95996e 100644
--- a/ud/confirmFact.go
+++ b/ud/confirmFact.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package ud
 
 import (
@@ -6,8 +13,8 @@ import (
 	pb "gitlab.com/elixxir/comms/mixmessages"
 )
 
-// ConfirmFact confirms a fact first registered via AddFact. The
-// confirmation ID comes from AddFact while the code will come over the
+// ConfirmFact confirms a fact first registered via SendRegisterFact. The
+// confirmation ID comes from SendRegisterFact while the code will come over the
 // associated communications system.
 func (m *Manager) ConfirmFact(confirmationID, code string) error {
 	jww.INFO.Printf("ud.ConfirmFact(%s, %s)", confirmationID, code)
diff --git a/ud/confirmFact_test.go b/ud/confirmFact_test.go
index b59a3c385a499ff9685c5520056ac3c59cb0c9b0..72c72260557f92e1c611e0073fd47407b41e5d40 100644
--- a/ud/confirmFact_test.go
+++ b/ud/confirmFact_test.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package ud
 
 import (
diff --git a/ud/generate.sh b/ud/generate.sh
deleted file mode 100755
index f8e0ec99843d0d39bf12b63f145d81a8df1bc99d..0000000000000000000000000000000000000000
--- a/ud/generate.sh
+++ /dev/null
@@ -1,3 +0,0 @@
-#!/bin/bash
-
-protoc --go_out=. udMessages.proto
diff --git a/ud/interfaces.go b/ud/interfaces.go
index addd3a5303c42f7d6e3ce5ddd075e6a43e14ed6d..9439d365c56441356477ee34c76fb5371c032c63 100644
--- a/ud/interfaces.go
+++ b/ud/interfaces.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package ud
 
 import (
diff --git a/ud/lookup.go b/ud/lookup.go
index cce461a9d0cb4676cb4f35cf9fdb4e175b9fd00c..569dc5b99578e9487c350028eb5e4649cbf8efc1 100644
--- a/ud/lookup.go
+++ b/ud/lookup.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package ud
 
 import (
diff --git a/ud/lookup_test.go b/ud/lookup_test.go
index 2b168e4a30c3b04e9840225c43b5e1aab039759c..4b4d61d65e4154cb94b831fe5c4bee44d1a01d11 100644
--- a/ud/lookup_test.go
+++ b/ud/lookup_test.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package ud
 
 import (
@@ -43,7 +50,7 @@ func TestManager_Lookup(t *testing.T) {
 		DhPubKey: publicKey,
 	}
 
-	contacts := []*Contact{&Contact{
+	contacts := []*Contact{{
 		UserID: expectedContact.ID.Bytes(),
 		PubKey: expectedContact.DhPubKey.Bytes(),
 	}}
diff --git a/ud/manager.go b/ud/manager.go
index 0a4247fb809d876b4c0659639827bc2929ba3b83..fd57a886b7046c09cfb33bf6a58adc0d752730e5 100644
--- a/ud/manager.go
+++ b/ud/manager.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package ud
 
 import (
@@ -37,6 +44,10 @@ type Manager struct {
 	// ud is the tracker for the contact information of the specified UD server.
 	// This information is specified in Manager's constructors (NewOrLoad and NewManagerFromBackup).
 	ud *userDiscovery
+
+	// nameService adheres to the channels.NameService interface. This is
+	// implemented using the clientIDTracker.
+	nameService *clientIDTracker
 }
 
 // NewOrLoad loads an existing Manager from storage or creates a
@@ -66,18 +77,34 @@ func NewOrLoad(user udE2e, comms Comms, follower udNetworkStatus,
 
 	jww.INFO.Println("ud.NewOrLoad()")
 
-	// Construct manager
-	m, err := loadOrNewManager(user, comms, follower)
-	if err != nil {
-		return nil, err
+	if follower() != xxdk.Running {
+		return nil, errors.New(
+			"cannot start UD Manager when network follower is not running.")
+	}
+
+	// Initialize manager
+	m := &Manager{
+		user:  user,
+		comms: comms,
 	}
 
 	// Set user discovery
-	err = m.setUserDiscovery(cert, contactFile, address)
+	err := m.setUserDiscovery(cert, contactFile, address)
 	if err != nil {
 		return nil, err
 	}
 
+	// Initialize store
+	m.store, err = store.NewOrLoadStore(m.getKv())
+	if err != nil {
+		return nil, errors.Errorf("Failed to initialize store: %v", err)
+	}
+
+	// If already registered, return
+	if IsRegistered(m.getKv()) {
+		return m, nil
+	}
+
 	// Register manager
 	rng := m.getRng().GetStream()
 	defer rng.Close()
@@ -86,7 +113,12 @@ func NewOrLoad(user udE2e, comms Comms, follower udNetworkStatus,
 		return nil, err
 	}
 
-	return m, nil
+	usernameFact, err := fact.NewFact(fact.Username, username)
+	if err != nil {
+		return nil, err
+	}
+
+	return m, m.store.StoreUsername(usernameFact)
 }
 
 // NewManagerFromBackup builds a new user discover manager from a backup.
@@ -111,7 +143,8 @@ func NewOrLoad(user udE2e, comms Comms, follower udNetworkStatus,
 // Returns
 //  - A Manager object which is registered to the specified UD service.
 func NewManagerFromBackup(user udE2e, comms Comms, follower udNetworkStatus,
-	email, phone fact.Fact, cert, contactFile []byte, address string) (*Manager, error) {
+	username, email, phone fact.Fact,
+	cert, contactFile []byte, address string) (*Manager, error) {
 	jww.INFO.Println("ud.NewManagerFromBackup()")
 	if follower() != xxdk.Running {
 		return nil, errors.New(
@@ -133,7 +166,7 @@ func NewManagerFromBackup(user udE2e, comms Comms, follower udNetworkStatus,
 	}
 
 	// Put any passed in missing facts into store
-	err = m.store.BackUpMissingFacts(email, phone)
+	err = m.store.BackUpMissingFacts(username, email, phone)
 	if err != nil {
 		return nil, errors.WithMessage(err, "Failed to restore UD store "+
 			"from backup")
@@ -164,7 +197,7 @@ func InitStoreFromBackup(kv *versioned.KV,
 	}
 
 	// Put any passed in missing facts into store
-	err = udStore.BackUpMissingFacts(email, phone)
+	err = udStore.BackUpMissingFacts(username, email, phone)
 	if err != nil {
 		return errors.WithMessage(err, "Failed to restore UD store "+
 			"from backup")
@@ -197,41 +230,6 @@ func (m *Manager) GetContact() contact.Contact {
 	return m.ud.contact
 }
 
-// loadOrNewManager is a helper function which loads from storage or
-// creates a new Manager object.
-func loadOrNewManager(user udE2e, comms Comms,
-	follower udNetworkStatus) (*Manager, error) {
-	if follower() != xxdk.Running {
-		return nil, errors.New(
-			"cannot start UD Manager when network follower is not running.")
-	}
-
-	// Initialize manager
-	m := &Manager{
-		user:  user,
-		comms: comms,
-	}
-
-	if m.isRegistered() {
-		// Load manager if already registered
-		var err error
-		m.store, err = store.NewOrLoadStore(m.getKv())
-		if err != nil {
-			return nil, errors.Errorf("Failed to initialize store: %v", err)
-		}
-		return m, nil
-	}
-
-	// Initialize store
-	var err error
-	m.store, err = store.NewOrLoadStore(m.getKv())
-	if err != nil {
-		return nil, errors.Errorf("Failed to initialize store: %v", err)
-	}
-
-	return m, nil
-}
-
 ////////////////////////////////////////////////////////////////////////////////
 // Internal Getters                                                           //
 ////////////////////////////////////////////////////////////////////////////////
@@ -242,7 +240,7 @@ func (m *Manager) getCmix() udCmix {
 	return m.user.GetCmix()
 }
 
-// getKv returns a versioned.KV used for isRegistered and setRegistered.
+// getKv returns a versioned.KV used for IsRegistered and setRegistered.
 // This is separated from store operations as store's kv
 // has a different prefix which breaks backwards compatibility.
 func (m *Manager) getKv() *versioned.KV {
diff --git a/ud/manager_test.go b/ud/manager_test.go
index b214c9600302170cc0822b8806ac8c8fe6de943b..c54e17977c2dbdeb047208ff0fd0d94b8784e1ba 100644
--- a/ud/manager_test.go
+++ b/ud/manager_test.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package ud
 
diff --git a/ud/mockComms_test.go b/ud/mockComms_test.go
index 542469eac332d27589dc6c40a27ef824f60a6cab..b77efc11a502e72036b343708e993ede522f46ba 100644
--- a/ud/mockComms_test.go
+++ b/ud/mockComms_test.go
@@ -1,14 +1,31 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package ud
 
 import (
-	pb "gitlab.com/elixxir/comms/mixmessages"
+	"crypto/ed25519"
+	"time"
+
 	"gitlab.com/xx_network/comms/connect"
 	"gitlab.com/xx_network/comms/messages"
+	"gitlab.com/xx_network/crypto/signature/rsa"
 	"gitlab.com/xx_network/primitives/id"
+
+	pb "gitlab.com/elixxir/comms/mixmessages"
+	"gitlab.com/elixxir/crypto/channel"
 )
 
 type mockComms struct {
-	udHost *connect.Host
+	udHost            *connect.Host
+	userRsaPub        *rsa.PublicKey
+	userEd25519PubKey []byte
+	udPrivKey         *ed25519.PrivateKey
+	username          string
 }
 
 func (m mockComms) SendRegisterUser(host *connect.Host, message *pb.UDBUserRegistration) (*messages.Ack, error) {
@@ -44,3 +61,44 @@ func (m *mockComms) AddHost(hid *id.ID, address string, cert []byte, params conn
 func (m mockComms) GetHost(hostId *id.ID) (*connect.Host, bool) {
 	return m.udHost, true
 }
+
+func (m *mockComms) SetUDEd25519PrivateKey(key *ed25519.PrivateKey) {
+	m.udPrivKey = key
+}
+
+func (m *mockComms) SetUserRSAPubKey(userRsaPub *rsa.PublicKey) {
+	m.userRsaPub = userRsaPub
+}
+
+func (m *mockComms) SetUsername(u string) {
+	m.username = u
+}
+
+func (m mockComms) SendChannelLeaseRequest(host *connect.Host, message *pb.ChannelLeaseRequest) (*pb.ChannelLeaseResponse, error) {
+
+	err := channel.VerifyChannelIdentityRequest(message.UserPubKeyRSASignature,
+		message.UserEd25519PubKey,
+		time.Now(),
+		time.Unix(0, message.Timestamp),
+		m.userRsaPub)
+	if err != nil {
+		panic(err)
+	}
+
+	d, _ := time.ParseDuration("4h30m")
+	lease := time.Now().Add(d).UnixNano()
+	signature := channel.SignChannelLease(message.UserEd25519PubKey, m.username,
+		time.Unix(0, lease), *m.udPrivKey)
+
+	if err != nil {
+		panic(err)
+	}
+
+	response := &pb.ChannelLeaseResponse{
+		Lease:                   lease,
+		UserEd25519PubKey:       m.userEd25519PubKey,
+		UDLeaseEd25519Signature: signature,
+	}
+
+	return response, nil
+}
diff --git a/ud/mockE2e_test.go b/ud/mockE2e_test.go
index c57e148fe6a63845a480bebb1aa939789b600bfc..e903d7eb59819ddb0445a7167cd4ebfd45c2361a 100644
--- a/ud/mockE2e_test.go
+++ b/ud/mockE2e_test.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package ud
 
 import (
@@ -109,7 +116,7 @@ func (m mockE2eHandler) StartProcesses() (stoppable.Stoppable, error) {
 	panic("implement me")
 }
 
-func (m mockE2eHandler) SendE2E(mt catalog.MessageType, recipient *id.ID, payload []byte, params e2e.Params) ([]id.Round, cryptoE2e.MessageID, time.Time, error) {
+func (m mockE2eHandler) SendE2E(mt catalog.MessageType, recipient *id.ID, payload []byte, params e2e.Params) (cryptoE2e.SendReport, error) {
 	//TODO implement me
 	panic("implement me")
 }
diff --git a/ud/mockStore_test.go b/ud/mockStore_test.go
index 5031f491bbfa8b8f24ca35c9f57d3b5dd6df0575..6e1b336d9e25246f5bc76bae47c5ebddfd2db96a 100644
--- a/ud/mockStore_test.go
+++ b/ud/mockStore_test.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package ud
 
 import (
diff --git a/ud/networkManager_test.go b/ud/networkManager_test.go
index 3af69d9efaab5db21c45ea17f46c21313bb4e197..bd3630ebf9016e37535dbba6ea332c5676da4a1a 100644
--- a/ud/networkManager_test.go
+++ b/ud/networkManager_test.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package ud
 
 import (
@@ -27,9 +34,44 @@ type testNetworkManager struct {
 	responseProcessor message.Processor
 }
 
+func (tnm *testNetworkManager) SendWithAssembler(recipient *id.ID, assembler cmix.MessageAssembler,
+	cmixParams cmix.CMIXParams) (rounds.Round, ephemeral.Id, error) {
+
+	msg := format.NewMessage(tnm.instance.GetE2EGroup().GetP().ByteLen())
+
+	var rid id.Round = 123
+	ephemeralId := new(ephemeral.Id)
+
+	fingerprint, service, payload, mac, err := assembler(rid)
+	if err != nil {
+		return rounds.Round{ID: rid}, *ephemeralId, err
+	}
+
+	// Build message. Will panic if inputs are not correct.
+	msg.SetKeyFP(fingerprint)
+	msg.SetContents(payload)
+	msg.SetMac(mac)
+	msg.SetSIH(service.Hash(msg.GetContents()))
+	// If the recipient for a call to Send is UD, then this
+	// is the request pathway. Call the UD processor to simulate
+	// the UD picking up the request
+	if bytes.Equal(tnm.instance.GetFullNdf().
+		Get().UDB.ID,
+		recipient.Bytes()) {
+		tnm.responseProcessor.Process(msg, receptionID.EphemeralIdentity{}, rounds.Round{})
+
+	} else {
+		// This should happen when the mock UD service Sends back a response.
+		// Calling process mocks up the requester picking up the response.
+		tnm.requestProcess.Process(msg, receptionID.EphemeralIdentity{}, rounds.Round{})
+	}
+
+	return rounds.Round{}, ephemeral.Id{}, nil
+}
+
 func (tnm *testNetworkManager) Send(recipient *id.ID, fingerprint format.Fingerprint,
 	service message.Service,
-	payload, mac []byte, cmixParams cmix.CMIXParams) (id.Round, ephemeral.Id, error) {
+	payload, mac []byte, cmixParams cmix.CMIXParams) (rounds.Round, ephemeral.Id, error) {
 	msg := format.NewMessage(tnm.instance.GetE2EGroup().GetP().ByteLen())
 	// Build message. Will panic if inputs are not correct.
 	msg.SetKeyFP(fingerprint)
@@ -50,7 +92,7 @@ func (tnm *testNetworkManager) Send(recipient *id.ID, fingerprint format.Fingerp
 		tnm.requestProcess.Process(msg, receptionID.EphemeralIdentity{}, rounds.Round{})
 	}
 
-	return 0, ephemeral.Id{}, nil
+	return rounds.Round{}, ephemeral.Id{}, nil
 }
 
 func (tnm *testNetworkManager) AddFingerprint(identity *id.ID,
@@ -129,7 +171,7 @@ func (tnm *testNetworkManager) SendToAny(sendFunc func(host *connect.Host) (inte
 	panic("implement me")
 }
 
-func (tnm *testNetworkManager) SendMany(messages []cmix.TargetedCmixMessage, p cmix.CMIXParams) (id.Round, []ephemeral.Id, error) {
+func (tnm *testNetworkManager) SendMany(messages []cmix.TargetedCmixMessage, p cmix.CMIXParams) (rounds.Round, []ephemeral.Id, error) {
 	//TODO implement me
 	panic("implement me")
 }
@@ -189,7 +231,7 @@ func (tnm *testNetworkManager) TriggerNodeRegistration(nid *id.ID) {
 	panic("implement me")
 }
 
-func (tnm *testNetworkManager) GetRoundResults(timeout time.Duration, roundCallback cmix.RoundEventCallback, roundList ...id.Round) error {
+func (tnm *testNetworkManager) GetRoundResults(timeout time.Duration, roundCallback cmix.RoundEventCallback, roundList ...id.Round) {
 	//TODO implement me
 	panic("implement me")
 }
diff --git a/ud/register.go b/ud/register.go
index 495d50da5e1fb51dd0e9d0e9d0211547d3314946..d70eaf0e2c71e80e859be942e19b3e6aa1196383 100644
--- a/ud/register.go
+++ b/ud/register.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package ud
 
 import (
@@ -19,7 +26,7 @@ func (m *Manager) register(username string, networkSignature []byte,
 
 	// Retrieve data used for registration
 	identity := m.user.GetReceptionIdentity()
-	privKey, err := identity.GetRSAPrivatePem()
+	privKey, err := identity.GetRSAPrivateKey()
 	if err != nil {
 		return err
 	}
diff --git a/ud/register_test.go b/ud/register_test.go
index f5c4f57828f27826ebd025354bc91a13cb81ec49..3d89b7245493e493a20974c990f45fb2cd49cc4f 100644
--- a/ud/register_test.go
+++ b/ud/register_test.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package ud
 
 import (
diff --git a/ud/registered.go b/ud/registered.go
index 06dba95886e3d92717ae9d8143fbd3ca8bd3189c..f19bcc03e63adebe5b3992131e61af1cc91008e1 100644
--- a/ud/registered.go
+++ b/ud/registered.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package ud
 
 import (
@@ -11,10 +18,10 @@ import (
 const isRegisteredKey = "isRegisteredKey"
 const isRegisteredVersion = 0
 
-// isRegistered loads from storage if the user is registered with user
+// IsRegistered loads from storage if the user is registered with user
 // discovery.
-func (m *Manager) isRegistered() bool {
-	_, err := m.getKv().Get(isRegisteredKey, isRegisteredVersion)
+func IsRegistered(kv *versioned.KV) bool {
+	_, err := kv.Get(isRegisteredKey, isRegisteredVersion)
 	if err != nil {
 		return false
 	}
@@ -32,7 +39,7 @@ func setRegistered(kv *versioned.KV) error {
 		Data:      data,
 	}
 
-	if err := kv.Set(isRegisteredKey, isRegisteredVersion, obj); err != nil {
+	if err := kv.Set(isRegisteredKey, obj); err != nil {
 		jww.FATAL.Panicf("Failed to store that the client is "+
 			"registered: %+v", err)
 	}
diff --git a/ud/remove.go b/ud/remove.go
index ebb809c0022ab0bbc81237c092c106bcbf946bd2..71db207ed6c263e8024f3df6cd1e56aba3cb8a29 100644
--- a/ud/remove.go
+++ b/ud/remove.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package ud
 
 import (
@@ -40,7 +47,7 @@ func (m *Manager) removeFact(f fact.Fact,
 
 	// Sign our inFact for putting into the request
 	identity := m.user.GetReceptionIdentity()
-	privKey, err := identity.GetRSAPrivatePem()
+	privKey, err := identity.GetRSAPrivateKey()
 	if err != nil {
 		return err
 	}
@@ -78,7 +85,7 @@ func (m *Manager) PermanentDeleteAccount(f fact.Fact) error {
 			"a username. Cannot remove fact %q", f.Fact))
 	}
 	identity := m.user.GetReceptionIdentity()
-	privKey, err := identity.GetRSAPrivatePem()
+	privKey, err := identity.GetRSAPrivateKey()
 	if err != nil {
 		return err
 	}
diff --git a/ud/remove_test.go b/ud/remove_test.go
index 53b61b3fae3070c08dad9d5d9d8c9d69503b0371..211bff6ae3516908e5b93efbd831cb3378ee7278 100644
--- a/ud/remove_test.go
+++ b/ud/remove_test.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package ud
 
 //type testRFC struct{}
diff --git a/ud/search.go b/ud/search.go
index dee22789df5cd285bd31835f00c134eac8bdbee3..43bf08518350929df2c652724bf8706e1ac74b38 100644
--- a/ud/search.go
+++ b/ud/search.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package ud
 
 import (
diff --git a/ud/search_test.go b/ud/search_test.go
index 3130e4f9b524a0cd79360a1bbcd42c4430052e8d..596d7768d191a05368f50e663f4d23dd04765cf4 100644
--- a/ud/search_test.go
+++ b/ud/search_test.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package ud
 
 import (
diff --git a/ud/store/facts.go b/ud/store/facts.go
index 202d8814bf5748ad5c7f8bf77c68ca26344fa842..4721b864ead28fb44a6e2a3c7bd7b87196d4c9f8 100644
--- a/ud/store/facts.go
+++ b/ud/store/facts.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package ud
 
@@ -42,6 +42,42 @@ func (s *Store) RestoreFromBackUp(backupData fact.FactList) error {
 	return s.save()
 }
 
+// StoreUsername forces the storage of a username fact.Fact into the
+// Store's confirmedFacts map. The passed in fact.Fact must be of
+// type fact.Username or this will not store the username.
+func (s *Store) StoreUsername(f fact.Fact) error {
+	s.mux.Lock()
+	defer s.mux.Unlock()
+
+	if f.T != fact.Username {
+		return errors.Errorf("Fact (%s) is not of type username", f.Stringify())
+	}
+
+	s.confirmedFacts[f] = struct{}{}
+
+	return s.saveConfirmedFacts()
+}
+
+// GetUsername retrieves the username from the Store object.
+// If it is not directly in the Store's username field, it is
+// searched for in the map.
+func (s *Store) GetUsername() (string, error) {
+	s.mux.RLock()
+	defer s.mux.RUnlock()
+
+	// todo: refactor this in the future so that
+	//  it's an O(1) lookup (place this object in another map
+	//  or have it's own field)
+	for f := range s.confirmedFacts {
+		if f.T == fact.Username {
+			return f.Fact, nil
+		}
+	}
+
+	return "", errors.New("Could not find username in store")
+
+}
+
 // StoreUnconfirmedFact stores a fact that has been added to UD but has not been
 // confirmed by the user. It is keyed on the confirmation ID given by UD.
 func (s *Store) StoreUnconfirmedFact(confirmationId string, f fact.Fact) error {
@@ -84,11 +120,11 @@ func (s *Store) ConfirmFact(confirmationId string) error {
 // If you attempt to back up a fact type that has already been backed up,
 // an error will be returned and nothing will be backed up.
 // Otherwise, it adds the fact and returns whether the Store saved successfully.
-func (s *Store) BackUpMissingFacts(email, phone fact.Fact) error {
+func (s *Store) BackUpMissingFacts(username, email, phone fact.Fact) error {
 	s.mux.Lock()
 	defer s.mux.Unlock()
 
-	modifiedEmail, modifiedPhone := false, false
+	modified := false
 
 	// Handle email if it is not zero (empty string)
 	if !isFactZero(email) {
@@ -102,10 +138,12 @@ func (s *Store) BackUpMissingFacts(email, phone fact.Fact) error {
 			// If an email exists in memory, return an error
 			return errors.Errorf(factTypeExistsErr, email, fact.Email)
 		} else {
-			modifiedEmail = true
+			s.confirmedFacts[email] = struct{}{}
+			modified = true
 		}
 	}
 
+	// Handle phone if it is not an empty string
 	if !isFactZero(phone) {
 		// check if fact is expected type
 		if phone.T != fact.Phone {
@@ -117,19 +155,24 @@ func (s *Store) BackUpMissingFacts(email, phone fact.Fact) error {
 			// If a phone exists in memory, return an error
 			return errors.Errorf(factTypeExistsErr, phone, fact.Phone)
 		} else {
-			modifiedPhone = true
+			s.confirmedFacts[phone] = struct{}{}
+			modified = true
 		}
 	}
 
-	if modifiedPhone || modifiedEmail {
-		if modifiedEmail {
-			s.confirmedFacts[email] = struct{}{}
-		}
-
-		if modifiedPhone {
-			s.confirmedFacts[phone] = struct{}{}
+	if !isFactZero(username) {
+		// Check if fact type is already in map. You should not be able to
+		// overwrite your username.
+		if isFactTypeInMap(fact.Username, s.confirmedFacts) {
+			// If a username exists in memory, return an error
+			return errors.Errorf(factTypeExistsErr, username, fact.Username)
+		} else {
+			s.confirmedFacts[username] = struct{}{}
+			modified = true
 		}
+	}
 
+	if modified {
 		return s.saveConfirmedFacts()
 	}
 
diff --git a/ud/store/facts_test.go b/ud/store/facts_test.go
index 332b5289da335390d76df7f41adbb49f2bd2d975..3155d383b36e7eb95d218f3389fa62e0ba9be0b6 100644
--- a/ud/store/facts_test.go
+++ b/ud/store/facts_test.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package ud
 
@@ -20,9 +20,9 @@ func TestNewStore(t *testing.T) {
 
 	kv := versioned.NewKV(ekv.MakeMemstore())
 
-	_, err := NewStore(kv)
+	_, err := newStore(kv)
 	if err != nil {
-		t.Errorf("NewStore() produced an error: %v", err)
+		t.Errorf("newStore() produced an error: %v", err)
 	}
 
 }
@@ -32,9 +32,9 @@ func TestStore_RestoreFromBackUp(t *testing.T) {
 
 	kv := versioned.NewKV(ekv.MakeMemstore())
 
-	s, err := NewStore(kv)
+	s, err := newStore(kv)
 	if err != nil {
-		t.Errorf("NewStore() produced an error: %v", err)
+		t.Errorf("newStore() produced an error: %v", err)
 	}
 
 	expected := fact.Fact{
@@ -61,9 +61,9 @@ func TestStore_RestoreFromBackUp_StatefulStore(t *testing.T) {
 
 	kv := versioned.NewKV(ekv.MakeMemstore())
 
-	s, err := NewStore(kv)
+	s, err := newStore(kv)
 	if err != nil {
-		t.Errorf("NewStore() produced an error: %v", err)
+		t.Errorf("newStore() produced an error: %v", err)
 	}
 
 	confirmId := "confirm"
@@ -90,9 +90,9 @@ func TestStore_RestoreFromBackUp_StatefulStore(t *testing.T) {
 func TestStore_ConfirmFact(t *testing.T) {
 	kv := versioned.NewKV(ekv.MakeMemstore())
 
-	expectedStore, err := NewStore(kv)
+	expectedStore, err := newStore(kv)
 	if err != nil {
-		t.Errorf("NewStore() produced an error: %v", err)
+		t.Errorf("newStore() produced an error: %v", err)
 	}
 
 	confirmId := "confirm"
@@ -128,9 +128,9 @@ func TestStore_ConfirmFact(t *testing.T) {
 func TestStore_StoreUnconfirmedFact(t *testing.T) {
 	kv := versioned.NewKV(ekv.MakeMemstore())
 
-	expectedStore, err := NewStore(kv)
+	expectedStore, err := newStore(kv)
 	if err != nil {
-		t.Errorf("NewStore() produced an error: %v", err)
+		t.Errorf("newStore() produced an error: %v", err)
 	}
 
 	confirmId := "confirm"
@@ -156,9 +156,9 @@ func TestStore_StoreUnconfirmedFact(t *testing.T) {
 func TestStore_DeleteFact(t *testing.T) {
 	kv := versioned.NewKV(ekv.MakeMemstore())
 
-	expectedStore, err := NewStore(kv)
+	expectedStore, err := newStore(kv)
 	if err != nil {
-		t.Errorf("NewStore() produced an error: %v", err)
+		t.Errorf("newStore() produced an error: %v", err)
 	}
 
 	expected := fact.Fact{
@@ -188,9 +188,9 @@ func TestStore_DeleteFact(t *testing.T) {
 func TestStore_BackUpMissingFacts(t *testing.T) {
 	kv := versioned.NewKV(ekv.MakeMemstore())
 
-	expectedStore, err := NewStore(kv)
+	expectedStore, err := newStore(kv)
 	if err != nil {
-		t.Errorf("NewStore() produced an error: %v", err)
+		t.Errorf("newStore() produced an error: %v", err)
 	}
 
 	email := fact.Fact{
@@ -203,7 +203,12 @@ func TestStore_BackUpMissingFacts(t *testing.T) {
 		T:    fact.Phone,
 	}
 
-	err = expectedStore.BackUpMissingFacts(email, phone)
+	username := fact.Fact{
+		Fact: "admin",
+		T:    fact.Username,
+	}
+
+	err = expectedStore.BackUpMissingFacts(username, email, phone)
 	if err != nil {
 		t.Fatalf("BackUpMissingFacts() produced an error: %v", err)
 	}
@@ -223,9 +228,9 @@ func TestStore_BackUpMissingFacts(t *testing.T) {
 func TestStore_BackUpMissingFacts_DuplicateFactType(t *testing.T) {
 	kv := versioned.NewKV(ekv.MakeMemstore())
 
-	expectedStore, err := NewStore(kv)
+	expectedStore, err := newStore(kv)
 	if err != nil {
-		t.Errorf("NewStore() produced an error: %v", err)
+		t.Errorf("newStore() produced an error: %v", err)
 	}
 
 	email := fact.Fact{
@@ -238,18 +243,23 @@ func TestStore_BackUpMissingFacts_DuplicateFactType(t *testing.T) {
 		T:    fact.Phone,
 	}
 
-	err = expectedStore.BackUpMissingFacts(email, phone)
+	username := fact.Fact{
+		Fact: "admin",
+		T:    fact.Username,
+	}
+
+	err = expectedStore.BackUpMissingFacts(username, email, phone)
 	if err != nil {
 		t.Fatalf("BackUpMissingFacts() produced an error: %v", err)
 	}
 
-	err = expectedStore.BackUpMissingFacts(email, fact.Fact{})
+	err = expectedStore.BackUpMissingFacts(username, email, fact.Fact{})
 	if err == nil {
 		t.Fatalf("BackUpMissingFacts() should not allow backing up an "+
 			"email when an email has already been backed up: %v", err)
 	}
 
-	err = expectedStore.BackUpMissingFacts(fact.Fact{}, phone)
+	err = expectedStore.BackUpMissingFacts(username, fact.Fact{}, phone)
 	if err == nil {
 		t.Fatalf("BackUpMissingFacts() should not allow backing up a "+
 			"phone number when a phone number has already been backed up: %v", err)
@@ -260,9 +270,9 @@ func TestStore_BackUpMissingFacts_DuplicateFactType(t *testing.T) {
 func TestStore_GetFacts(t *testing.T) {
 	kv := versioned.NewKV(ekv.MakeMemstore())
 
-	testStore, err := NewStore(kv)
+	testStore, err := newStore(kv)
 	if err != nil {
-		t.Errorf("NewStore() produced an error: %v", err)
+		t.Errorf("newStore() produced an error: %v", err)
 	}
 
 	emailFact := fact.Fact{
@@ -272,7 +282,12 @@ func TestStore_GetFacts(t *testing.T) {
 
 	emptyFact := fact.Fact{}
 
-	err = testStore.BackUpMissingFacts(emailFact, emptyFact)
+	username := fact.Fact{
+		Fact: "admin",
+		T:    fact.Username,
+	}
+
+	err = testStore.BackUpMissingFacts(username, emailFact, emptyFact)
 	if err != nil {
 		t.Fatalf("Faild to add fact %v: %v", emailFact, err)
 	}
@@ -282,12 +297,12 @@ func TestStore_GetFacts(t *testing.T) {
 		T:    fact.Phone,
 	}
 
-	err = testStore.BackUpMissingFacts(emptyFact, phoneFact)
+	err = testStore.BackUpMissingFacts(emptyFact, emptyFact, phoneFact)
 	if err != nil {
 		t.Fatalf("Faild to add fact %v: %v", phoneFact, err)
 	}
 
-	expectedFacts := []fact.Fact{emailFact, phoneFact}
+	expectedFacts := []fact.Fact{username, emailFact, phoneFact}
 
 	receivedFacts := testStore.GetFacts()
 
@@ -309,19 +324,23 @@ func TestStore_GetFacts(t *testing.T) {
 func TestStore_GetFactStrings(t *testing.T) {
 	kv := versioned.NewKV(ekv.MakeMemstore())
 
-	testStore, err := NewStore(kv)
+	testStore, err := newStore(kv)
 	if err != nil {
-		t.Errorf("NewStore() produced an error: %v", err)
+		t.Errorf("newStore() produced an error: %v", err)
 	}
 
 	emailFact := fact.Fact{
 		Fact: "josh@elixxir.io",
 		T:    fact.Email,
 	}
+	username := fact.Fact{
+		Fact: "admin",
+		T:    fact.Username,
+	}
 
 	emptyFact := fact.Fact{}
 
-	err = testStore.BackUpMissingFacts(emailFact, emptyFact)
+	err = testStore.BackUpMissingFacts(username, emailFact, emptyFact)
 	if err != nil {
 		t.Fatalf("Faild to add fact %v: %v", emailFact, err)
 	}
@@ -331,12 +350,12 @@ func TestStore_GetFactStrings(t *testing.T) {
 		T:    fact.Phone,
 	}
 
-	err = testStore.BackUpMissingFacts(emptyFact, phoneFact)
+	err = testStore.BackUpMissingFacts(emptyFact, emptyFact, phoneFact)
 	if err != nil {
 		t.Fatalf("Faild to add fact %v: %v", phoneFact, err)
 	}
 
-	expectedFacts := []string{emailFact.Stringify(), phoneFact.Stringify()}
+	expectedFacts := []string{username.Stringify(), emailFact.Stringify(), phoneFact.Stringify()}
 
 	receivedFacts := testStore.GetStringifiedFacts()
 	sort.SliceStable(receivedFacts, func(i, j int) bool {
diff --git a/ud/store/store.go b/ud/store/store.go
index 0cf274add91a8d08791e7b0c189b8d190d0f7962..5e5cfaaa8af245e9467e08bd4fa8d809c4b77b10 100644
--- a/ud/store/store.go
+++ b/ud/store/store.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package ud
 
 // This file handles the storage operations on facts.
@@ -8,8 +15,6 @@ import (
 	"gitlab.com/elixxir/client/storage/versioned"
 	"gitlab.com/elixxir/primitives/fact"
 	"gitlab.com/xx_network/primitives/netTime"
-	"io/fs"
-	"strings"
 	"sync"
 )
 
@@ -23,8 +28,7 @@ const (
 
 // Error constants
 const (
-	malformedFactErr = "Failed to load due to " +
-		"malformed fact"
+	malformedFactErr       = "Failed to load due to malformed fact %s"
 	loadConfirmedFactErr   = "Failed to load confirmed facts"
 	loadUnconfirmedFactErr = "Failed to load unconfirmed facts"
 	saveUnconfirmedFactErr = "Failed to save unconfirmed facts"
@@ -43,13 +47,13 @@ type Store struct {
 	mux              sync.RWMutex
 }
 
-// NewStore creates a new, empty Store object.
-func NewStore(kv *versioned.KV) (*Store, error) {
+// newStore creates a new, empty Store object.
+func newStore(kv *versioned.KV) (*Store, error) {
 	kv = kv.Prefix(prefix)
 
 	s := &Store{
-		confirmedFacts:   make(map[fact.Fact]struct{}, 0),
-		unconfirmedFacts: make(map[string]fact.Fact, 0),
+		confirmedFacts:   make(map[fact.Fact]struct{}),
+		unconfirmedFacts: make(map[string]fact.Fact),
 		kv:               kv,
 	}
 
@@ -94,7 +98,7 @@ func (s *Store) saveConfirmedFacts() error {
 	}
 
 	// Save to storage
-	return s.kv.Set(confirmedFactKey, version, &obj)
+	return s.kv.Set(confirmedFactKey, &obj)
 }
 
 // saveUnconfirmedFacts saves all data within Store.unconfirmedFacts into storage.
@@ -113,7 +117,7 @@ func (s *Store) saveUnconfirmedFacts() error {
 	}
 
 	// Save to storage
-	return s.kv.Set(unconfirmedFactKey, version, &obj)
+	return s.kv.Set(unconfirmedFactKey, &obj)
 
 }
 
@@ -125,15 +129,13 @@ func (s *Store) saveUnconfirmedFacts() error {
 func NewOrLoadStore(kv *versioned.KV) (*Store, error) {
 
 	s := &Store{
-		confirmedFacts:   make(map[fact.Fact]struct{}, 0),
-		unconfirmedFacts: make(map[string]fact.Fact, 0),
-		kv:               kv.Prefix(prefix),
+		kv: kv.Prefix(prefix),
 	}
-
 	if err := s.load(); err != nil {
-		if strings.Contains(err.Error(), "object not found") ||
-			errors.Is(err, fs.ErrNotExist) {
-			return s, s.save()
+		if !s.kv.Exists(err) {
+			return newStore(kv)
+		} else {
+			return nil, err
 		}
 	}
 
@@ -199,11 +201,11 @@ func (s *Store) loadUnconfirmedFacts() error {
 /////////////////////////////////////////////////////////////////
 
 // unconfirmedFactDisk is an object used to store the data of an unconfirmed fact.
-// It combines the key (confirmationId) and fact data (stringifiedFact) into a
+// It combines the key (ConfirmationId) and fact data (StringifiedFact) into a
 // single JSON-able object.
 type unconfirmedFactDisk struct {
-	confirmationId  string
-	stringifiedFact string
+	ConfirmationId  string
+	StringifiedFact string
 }
 
 // marshalConfirmedFacts is a marshaller which serializes the data
@@ -223,8 +225,8 @@ func (s *Store) marshalUnconfirmedFacts() ([]byte, error) {
 	ufdList := make([]unconfirmedFactDisk, 0, len(s.unconfirmedFacts))
 	for confirmationId, f := range s.unconfirmedFacts {
 		ufd := unconfirmedFactDisk{
-			confirmationId:  confirmationId,
-			stringifiedFact: f.Stringify(),
+			ConfirmationId:  confirmationId,
+			StringifiedFact: f.Stringify(),
 		}
 		ufdList = append(ufdList, ufd)
 	}
@@ -244,10 +246,12 @@ func (s *Store) unmarshalConfirmedFacts(data []byte) (map[fact.Fact]struct{}, er
 
 	// Deserialize the list into a map
 	confirmedFacts := make(map[fact.Fact]struct{}, 0)
-	for _, fStr := range fStrings {
+	for i := range fStrings {
+		fStr := fStrings[i]
 		f, err := fact.UnstringifyFact(fStr)
 		if err != nil {
-			return nil, errors.WithMessage(err, malformedFactErr)
+			return confirmedFacts, errors.WithMessagef(err,
+				malformedFactErr, string(data))
 		}
 
 		confirmedFacts[f] = struct{}{}
@@ -268,13 +272,15 @@ func (s *Store) unmarshalUnconfirmedFacts(data []byte) (map[string]fact.Fact, er
 
 	// Deserialize the list into a map
 	unconfirmedFacts := make(map[string]fact.Fact, 0)
-	for _, ufd := range ufdList {
-		f, err := fact.UnstringifyFact(ufd.stringifiedFact)
+	for i := range ufdList {
+		ufd := ufdList[i]
+		f, err := fact.UnstringifyFact(ufd.StringifiedFact)
 		if err != nil {
-			return nil, errors.WithMessage(err, malformedFactErr)
+			return unconfirmedFacts, errors.WithMessagef(err,
+				malformedFactErr, string(data))
 		}
 
-		unconfirmedFacts[ufd.confirmationId] = f
+		unconfirmedFacts[ufd.ConfirmationId] = f
 	}
 
 	return unconfirmedFacts, nil
diff --git a/ud/store/store_test.go b/ud/store/store_test.go
index ed56cb67c2a320cea8073e3baa8287998a65763f..a319d81284e122e420c89efc3a3828826c95ae3a 100644
--- a/ud/store/store_test.go
+++ b/ud/store/store_test.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package ud
 
 import (
@@ -13,9 +20,9 @@ import (
 func TestNewOrLoadStore_LoadStore(t *testing.T) {
 	kv := versioned.NewKV(ekv.MakeMemstore())
 
-	expectedStore, err := NewStore(kv)
+	expectedStore, err := newStore(kv)
 	if err != nil {
-		t.Errorf("NewStore() produced an error: %v", err)
+		t.Errorf("newStore() produced an error: %v", err)
 	}
 
 	receivedStore, err := NewOrLoadStore(kv)
@@ -59,9 +66,9 @@ func TestNewOrLoadStore_NewStore(t *testing.T) {
 func TestStore_MarshalUnmarshal_ConfirmedFacts(t *testing.T) {
 	kv := versioned.NewKV(ekv.MakeMemstore())
 
-	expectedStore, err := NewStore(kv)
+	expectedStore, err := newStore(kv)
 	if err != nil {
-		t.Errorf("NewStore() produced an error: %v", err)
+		t.Errorf("newStore() produced an error: %v", err)
 	}
 
 	data, err := expectedStore.kv.Get(confirmedFactKey, version)
@@ -75,7 +82,7 @@ func TestStore_MarshalUnmarshal_ConfirmedFacts(t *testing.T) {
 	}
 
 	if !bytes.Equal(expectedData, data.Data) {
-		t.Errorf("NewStore() returned incorrect Store."+
+		t.Errorf("newStore() returned incorrect Store."+
 			"\nexpected: %+v\nreceived: %+v", expectedData,
 			data.Data)
 	}
@@ -95,9 +102,9 @@ func TestStore_MarshalUnmarshal_ConfirmedFacts(t *testing.T) {
 func TestStore_MarshalUnmarshal_UnconfirmedFacts(t *testing.T) {
 	kv := versioned.NewKV(ekv.MakeMemstore())
 
-	expectedStore, err := NewStore(kv)
+	expectedStore, err := newStore(kv)
 	if err != nil {
-		t.Errorf("NewStore() produced an error: %v", err)
+		t.Errorf("newStore() produced an error: %v", err)
 	}
 
 	data, err := expectedStore.kv.Get(unconfirmedFactKey, version)
@@ -111,7 +118,7 @@ func TestStore_MarshalUnmarshal_UnconfirmedFacts(t *testing.T) {
 	}
 
 	if !bytes.Equal(expectedData, data.Data) {
-		t.Errorf("NewStore() returned incorrect Store."+
+		t.Errorf("newStore() returned incorrect Store."+
 			"\nexpected: %+v\nreceived: %+v", expectedData,
 			data.Data)
 	}
diff --git a/ud/ud.go b/ud/ud.go
index 5fb27e619de9d5196b24022b35277f1f26c37837..6788b9e99388b16cd64b0d91b50d9f43f26b642f 100644
--- a/ud/ud.go
+++ b/ud/ud.go
@@ -1,10 +1,16 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package ud
 
 import (
 	"github.com/pkg/errors"
 	"gitlab.com/elixxir/crypto/contact"
 	"gitlab.com/xx_network/comms/connect"
-	"gitlab.com/xx_network/primitives/id"
 	"time"
 )
 
@@ -23,35 +29,26 @@ func (m *Manager) setUserDiscovery(cert,
 	params.AuthEnabled = false
 	params.SendTimeout = 20 * time.Second
 
-	udIdBytes, dhPubKeyBytes, err := contact.ReadContactFromFile(contactFile)
-	if err != nil {
-		return err
-	}
-
-	udID, err := id.Unmarshal(udIdBytes)
+	// Unmarshal the new contact
+	con, err := contact.Unmarshal(contactFile)
 	if err != nil {
 		return err
 	}
 
 	// Add a new host and return it if it does not already exist
-	host, err := m.comms.AddHost(udID, address,
+	host, err := m.comms.AddHost(con.ID, address,
 		cert, params)
 	if err != nil {
 		return errors.WithMessage(err, "User Discovery host object could "+
 			"not be constructed.")
 	}
 
-	dhPubKey := m.user.GetE2E().GetGroup().NewInt(1)
-	err = dhPubKey.UnmarshalJSON(dhPubKeyBytes)
-	if err != nil {
-		return err
-	}
-
+	// Set the user discovery object within the manager
 	m.ud = &userDiscovery{
 		host: host,
 		contact: contact.Contact{
-			ID:       udID,
-			DhPubKey: dhPubKey,
+			ID:       con.ID,
+			DhPubKey: con.DhPubKey,
 		},
 	}
 
diff --git a/ud/udMessages.pb.go b/ud/udMessages.pb.go
index 0aae2063325f57b73c42ff53e30020225aefcd7e..8a4745c74317c8934d10f2943af4cc79c0d8dc6d 100644
--- a/ud/udMessages.pb.go
+++ b/ud/udMessages.pb.go
@@ -1,69 +1,84 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 // Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// 	protoc-gen-go v1.27.1
+// 	protoc        v3.15.6
 // source: udMessages.proto
 
 package ud
 
 import (
-	fmt "fmt"
-	proto "github.com/golang/protobuf/proto"
-	math "math"
+	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+	reflect "reflect"
+	sync "sync"
 )
 
-// Reference imports to suppress errors if they are not otherwise used.
-var _ = proto.Marshal
-var _ = fmt.Errorf
-var _ = math.Inf
-
-// This is a compile-time assertion to ensure that this generated file
-// is compatible with the proto package it is being compiled against.
-// A compilation error at this line likely means your copy of the
-// proto package needs to be updated.
-const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
+const (
+	// Verify that this generated code is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+	// Verify that runtime/protoimpl is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
 
 // Contains the Hash and its Type
 type HashFact struct {
-	Hash                 []byte   `protobuf:"bytes,1,opt,name=hash,proto3" json:"hash,omitempty"`
-	Type                 int32    `protobuf:"varint,2,opt,name=type,proto3" json:"type,omitempty"`
-	XXX_NoUnkeyedLiteral struct{} `json:"-"`
-	XXX_unrecognized     []byte   `json:"-"`
-	XXX_sizecache        int32    `json:"-"`
-}
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
 
-func (m *HashFact) Reset()         { *m = HashFact{} }
-func (m *HashFact) String() string { return proto.CompactTextString(m) }
-func (*HashFact) ProtoMessage()    {}
-func (*HashFact) Descriptor() ([]byte, []int) {
-	return fileDescriptor_9e0cfdc16fb09bb6, []int{0}
+	Hash []byte `protobuf:"bytes,1,opt,name=hash,proto3" json:"hash,omitempty"`
+	Type int32  `protobuf:"varint,2,opt,name=type,proto3" json:"type,omitempty"`
 }
 
-func (m *HashFact) XXX_Unmarshal(b []byte) error {
-	return xxx_messageInfo_HashFact.Unmarshal(m, b)
-}
-func (m *HashFact) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
-	return xxx_messageInfo_HashFact.Marshal(b, m, deterministic)
-}
-func (m *HashFact) XXX_Merge(src proto.Message) {
-	xxx_messageInfo_HashFact.Merge(m, src)
+func (x *HashFact) Reset() {
+	*x = HashFact{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_udMessages_proto_msgTypes[0]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
 }
-func (m *HashFact) XXX_Size() int {
-	return xxx_messageInfo_HashFact.Size(m)
+
+func (x *HashFact) String() string {
+	return protoimpl.X.MessageStringOf(x)
 }
-func (m *HashFact) XXX_DiscardUnknown() {
-	xxx_messageInfo_HashFact.DiscardUnknown(m)
+
+func (*HashFact) ProtoMessage() {}
+
+func (x *HashFact) ProtoReflect() protoreflect.Message {
+	mi := &file_udMessages_proto_msgTypes[0]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
 }
 
-var xxx_messageInfo_HashFact proto.InternalMessageInfo
+// Deprecated: Use HashFact.ProtoReflect.Descriptor instead.
+func (*HashFact) Descriptor() ([]byte, []int) {
+	return file_udMessages_proto_rawDescGZIP(), []int{0}
+}
 
-func (m *HashFact) GetHash() []byte {
-	if m != nil {
-		return m.Hash
+func (x *HashFact) GetHash() []byte {
+	if x != nil {
+		return x.Hash
 	}
 	return nil
 }
 
-func (m *HashFact) GetType() int32 {
-	if m != nil {
-		return m.Type
+func (x *HashFact) GetType() int32 {
+	if x != nil {
+		return x.Type
 	}
 	return 0
 }
@@ -71,285 +86,458 @@ func (m *HashFact) GetType() int32 {
 // Describes a user lookup result. The ID, public key, and the
 // facts inputted that brought up this user.
 type Contact struct {
-	UserID               []byte      `protobuf:"bytes,1,opt,name=userID,proto3" json:"userID,omitempty"`
-	PubKey               []byte      `protobuf:"bytes,2,opt,name=pubKey,proto3" json:"pubKey,omitempty"`
-	Username             string      `protobuf:"bytes,3,opt,name=username,proto3" json:"username,omitempty"`
-	TrigFacts            []*HashFact `protobuf:"bytes,4,rep,name=trigFacts,proto3" json:"trigFacts,omitempty"`
-	XXX_NoUnkeyedLiteral struct{}    `json:"-"`
-	XXX_unrecognized     []byte      `json:"-"`
-	XXX_sizecache        int32       `json:"-"`
-}
-
-func (m *Contact) Reset()         { *m = Contact{} }
-func (m *Contact) String() string { return proto.CompactTextString(m) }
-func (*Contact) ProtoMessage()    {}
-func (*Contact) Descriptor() ([]byte, []int) {
-	return fileDescriptor_9e0cfdc16fb09bb6, []int{1}
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	UserID    []byte      `protobuf:"bytes,1,opt,name=userID,proto3" json:"userID,omitempty"`
+	PubKey    []byte      `protobuf:"bytes,2,opt,name=pubKey,proto3" json:"pubKey,omitempty"`
+	Username  string      `protobuf:"bytes,3,opt,name=username,proto3" json:"username,omitempty"`
+	TrigFacts []*HashFact `protobuf:"bytes,4,rep,name=trigFacts,proto3" json:"trigFacts,omitempty"`
+}
+
+func (x *Contact) Reset() {
+	*x = Contact{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_udMessages_proto_msgTypes[1]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
 }
 
-func (m *Contact) XXX_Unmarshal(b []byte) error {
-	return xxx_messageInfo_Contact.Unmarshal(m, b)
-}
-func (m *Contact) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
-	return xxx_messageInfo_Contact.Marshal(b, m, deterministic)
-}
-func (m *Contact) XXX_Merge(src proto.Message) {
-	xxx_messageInfo_Contact.Merge(m, src)
+func (x *Contact) String() string {
+	return protoimpl.X.MessageStringOf(x)
 }
-func (m *Contact) XXX_Size() int {
-	return xxx_messageInfo_Contact.Size(m)
-}
-func (m *Contact) XXX_DiscardUnknown() {
-	xxx_messageInfo_Contact.DiscardUnknown(m)
+
+func (*Contact) ProtoMessage() {}
+
+func (x *Contact) ProtoReflect() protoreflect.Message {
+	mi := &file_udMessages_proto_msgTypes[1]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
 }
 
-var xxx_messageInfo_Contact proto.InternalMessageInfo
+// Deprecated: Use Contact.ProtoReflect.Descriptor instead.
+func (*Contact) Descriptor() ([]byte, []int) {
+	return file_udMessages_proto_rawDescGZIP(), []int{1}
+}
 
-func (m *Contact) GetUserID() []byte {
-	if m != nil {
-		return m.UserID
+func (x *Contact) GetUserID() []byte {
+	if x != nil {
+		return x.UserID
 	}
 	return nil
 }
 
-func (m *Contact) GetPubKey() []byte {
-	if m != nil {
-		return m.PubKey
+func (x *Contact) GetPubKey() []byte {
+	if x != nil {
+		return x.PubKey
 	}
 	return nil
 }
 
-func (m *Contact) GetUsername() string {
-	if m != nil {
-		return m.Username
+func (x *Contact) GetUsername() string {
+	if x != nil {
+		return x.Username
 	}
 	return ""
 }
 
-func (m *Contact) GetTrigFacts() []*HashFact {
-	if m != nil {
-		return m.TrigFacts
+func (x *Contact) GetTrigFacts() []*HashFact {
+	if x != nil {
+		return x.TrigFacts
 	}
 	return nil
 }
 
 // Message sent to UDB to search for users
 type SearchSend struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
 	// PublicKey used in the registration
-	Fact                 []*HashFact `protobuf:"bytes,1,rep,name=fact,proto3" json:"fact,omitempty"`
-	XXX_NoUnkeyedLiteral struct{}    `json:"-"`
-	XXX_unrecognized     []byte      `json:"-"`
-	XXX_sizecache        int32       `json:"-"`
+	Fact []*HashFact `protobuf:"bytes,1,rep,name=fact,proto3" json:"fact,omitempty"`
 }
 
-func (m *SearchSend) Reset()         { *m = SearchSend{} }
-func (m *SearchSend) String() string { return proto.CompactTextString(m) }
-func (*SearchSend) ProtoMessage()    {}
-func (*SearchSend) Descriptor() ([]byte, []int) {
-	return fileDescriptor_9e0cfdc16fb09bb6, []int{2}
+func (x *SearchSend) Reset() {
+	*x = SearchSend{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_udMessages_proto_msgTypes[2]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
 }
 
-func (m *SearchSend) XXX_Unmarshal(b []byte) error {
-	return xxx_messageInfo_SearchSend.Unmarshal(m, b)
+func (x *SearchSend) String() string {
+	return protoimpl.X.MessageStringOf(x)
 }
-func (m *SearchSend) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
-	return xxx_messageInfo_SearchSend.Marshal(b, m, deterministic)
-}
-func (m *SearchSend) XXX_Merge(src proto.Message) {
-	xxx_messageInfo_SearchSend.Merge(m, src)
-}
-func (m *SearchSend) XXX_Size() int {
-	return xxx_messageInfo_SearchSend.Size(m)
-}
-func (m *SearchSend) XXX_DiscardUnknown() {
-	xxx_messageInfo_SearchSend.DiscardUnknown(m)
+
+func (*SearchSend) ProtoMessage() {}
+
+func (x *SearchSend) ProtoReflect() protoreflect.Message {
+	mi := &file_udMessages_proto_msgTypes[2]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
 }
 
-var xxx_messageInfo_SearchSend proto.InternalMessageInfo
+// Deprecated: Use SearchSend.ProtoReflect.Descriptor instead.
+func (*SearchSend) Descriptor() ([]byte, []int) {
+	return file_udMessages_proto_rawDescGZIP(), []int{2}
+}
 
-func (m *SearchSend) GetFact() []*HashFact {
-	if m != nil {
-		return m.Fact
+func (x *SearchSend) GetFact() []*HashFact {
+	if x != nil {
+		return x.Fact
 	}
 	return nil
 }
 
 // Message sent from UDB to client in response to a search
 type SearchResponse struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
 	// ID of the session created
-	Contacts             []*Contact `protobuf:"bytes,1,rep,name=contacts,proto3" json:"contacts,omitempty"`
-	Error                string     `protobuf:"bytes,3,opt,name=error,proto3" json:"error,omitempty"`
-	XXX_NoUnkeyedLiteral struct{}   `json:"-"`
-	XXX_unrecognized     []byte     `json:"-"`
-	XXX_sizecache        int32      `json:"-"`
+	Contacts []*Contact `protobuf:"bytes,1,rep,name=contacts,proto3" json:"contacts,omitempty"`
+	Error    string     `protobuf:"bytes,3,opt,name=error,proto3" json:"error,omitempty"`
 }
 
-func (m *SearchResponse) Reset()         { *m = SearchResponse{} }
-func (m *SearchResponse) String() string { return proto.CompactTextString(m) }
-func (*SearchResponse) ProtoMessage()    {}
-func (*SearchResponse) Descriptor() ([]byte, []int) {
-	return fileDescriptor_9e0cfdc16fb09bb6, []int{3}
+func (x *SearchResponse) Reset() {
+	*x = SearchResponse{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_udMessages_proto_msgTypes[3]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
 }
 
-func (m *SearchResponse) XXX_Unmarshal(b []byte) error {
-	return xxx_messageInfo_SearchResponse.Unmarshal(m, b)
-}
-func (m *SearchResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
-	return xxx_messageInfo_SearchResponse.Marshal(b, m, deterministic)
-}
-func (m *SearchResponse) XXX_Merge(src proto.Message) {
-	xxx_messageInfo_SearchResponse.Merge(m, src)
-}
-func (m *SearchResponse) XXX_Size() int {
-	return xxx_messageInfo_SearchResponse.Size(m)
+func (x *SearchResponse) String() string {
+	return protoimpl.X.MessageStringOf(x)
 }
-func (m *SearchResponse) XXX_DiscardUnknown() {
-	xxx_messageInfo_SearchResponse.DiscardUnknown(m)
+
+func (*SearchResponse) ProtoMessage() {}
+
+func (x *SearchResponse) ProtoReflect() protoreflect.Message {
+	mi := &file_udMessages_proto_msgTypes[3]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
 }
 
-var xxx_messageInfo_SearchResponse proto.InternalMessageInfo
+// Deprecated: Use SearchResponse.ProtoReflect.Descriptor instead.
+func (*SearchResponse) Descriptor() ([]byte, []int) {
+	return file_udMessages_proto_rawDescGZIP(), []int{3}
+}
 
-func (m *SearchResponse) GetContacts() []*Contact {
-	if m != nil {
-		return m.Contacts
+func (x *SearchResponse) GetContacts() []*Contact {
+	if x != nil {
+		return x.Contacts
 	}
 	return nil
 }
 
-func (m *SearchResponse) GetError() string {
-	if m != nil {
-		return m.Error
+func (x *SearchResponse) GetError() string {
+	if x != nil {
+		return x.Error
 	}
 	return ""
 }
 
 // Message sent to UDB for looking up a user
 type LookupSend struct {
-	UserID               []byte   `protobuf:"bytes,1,opt,name=userID,proto3" json:"userID,omitempty"`
-	XXX_NoUnkeyedLiteral struct{} `json:"-"`
-	XXX_unrecognized     []byte   `json:"-"`
-	XXX_sizecache        int32    `json:"-"`
-}
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
 
-func (m *LookupSend) Reset()         { *m = LookupSend{} }
-func (m *LookupSend) String() string { return proto.CompactTextString(m) }
-func (*LookupSend) ProtoMessage()    {}
-func (*LookupSend) Descriptor() ([]byte, []int) {
-	return fileDescriptor_9e0cfdc16fb09bb6, []int{4}
+	UserID []byte `protobuf:"bytes,1,opt,name=userID,proto3" json:"userID,omitempty"`
 }
 
-func (m *LookupSend) XXX_Unmarshal(b []byte) error {
-	return xxx_messageInfo_LookupSend.Unmarshal(m, b)
-}
-func (m *LookupSend) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
-	return xxx_messageInfo_LookupSend.Marshal(b, m, deterministic)
-}
-func (m *LookupSend) XXX_Merge(src proto.Message) {
-	xxx_messageInfo_LookupSend.Merge(m, src)
+func (x *LookupSend) Reset() {
+	*x = LookupSend{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_udMessages_proto_msgTypes[4]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
 }
-func (m *LookupSend) XXX_Size() int {
-	return xxx_messageInfo_LookupSend.Size(m)
+
+func (x *LookupSend) String() string {
+	return protoimpl.X.MessageStringOf(x)
 }
-func (m *LookupSend) XXX_DiscardUnknown() {
-	xxx_messageInfo_LookupSend.DiscardUnknown(m)
+
+func (*LookupSend) ProtoMessage() {}
+
+func (x *LookupSend) ProtoReflect() protoreflect.Message {
+	mi := &file_udMessages_proto_msgTypes[4]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
 }
 
-var xxx_messageInfo_LookupSend proto.InternalMessageInfo
+// Deprecated: Use LookupSend.ProtoReflect.Descriptor instead.
+func (*LookupSend) Descriptor() ([]byte, []int) {
+	return file_udMessages_proto_rawDescGZIP(), []int{4}
+}
 
-func (m *LookupSend) GetUserID() []byte {
-	if m != nil {
-		return m.UserID
+func (x *LookupSend) GetUserID() []byte {
+	if x != nil {
+		return x.UserID
 	}
 	return nil
 }
 
 // Message sent from UDB for looking up a user
 type LookupResponse struct {
-	PubKey               []byte   `protobuf:"bytes,1,opt,name=pubKey,proto3" json:"pubKey,omitempty"`
-	Username             string   `protobuf:"bytes,2,opt,name=username,proto3" json:"username,omitempty"`
-	Error                string   `protobuf:"bytes,3,opt,name=error,proto3" json:"error,omitempty"`
-	XXX_NoUnkeyedLiteral struct{} `json:"-"`
-	XXX_unrecognized     []byte   `json:"-"`
-	XXX_sizecache        int32    `json:"-"`
-}
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
 
-func (m *LookupResponse) Reset()         { *m = LookupResponse{} }
-func (m *LookupResponse) String() string { return proto.CompactTextString(m) }
-func (*LookupResponse) ProtoMessage()    {}
-func (*LookupResponse) Descriptor() ([]byte, []int) {
-	return fileDescriptor_9e0cfdc16fb09bb6, []int{5}
+	PubKey   []byte `protobuf:"bytes,1,opt,name=pubKey,proto3" json:"pubKey,omitempty"`
+	Username string `protobuf:"bytes,2,opt,name=username,proto3" json:"username,omitempty"`
+	Error    string `protobuf:"bytes,3,opt,name=error,proto3" json:"error,omitempty"`
 }
 
-func (m *LookupResponse) XXX_Unmarshal(b []byte) error {
-	return xxx_messageInfo_LookupResponse.Unmarshal(m, b)
-}
-func (m *LookupResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
-	return xxx_messageInfo_LookupResponse.Marshal(b, m, deterministic)
-}
-func (m *LookupResponse) XXX_Merge(src proto.Message) {
-	xxx_messageInfo_LookupResponse.Merge(m, src)
+func (x *LookupResponse) Reset() {
+	*x = LookupResponse{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_udMessages_proto_msgTypes[5]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
 }
-func (m *LookupResponse) XXX_Size() int {
-	return xxx_messageInfo_LookupResponse.Size(m)
+
+func (x *LookupResponse) String() string {
+	return protoimpl.X.MessageStringOf(x)
 }
-func (m *LookupResponse) XXX_DiscardUnknown() {
-	xxx_messageInfo_LookupResponse.DiscardUnknown(m)
+
+func (*LookupResponse) ProtoMessage() {}
+
+func (x *LookupResponse) ProtoReflect() protoreflect.Message {
+	mi := &file_udMessages_proto_msgTypes[5]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
 }
 
-var xxx_messageInfo_LookupResponse proto.InternalMessageInfo
+// Deprecated: Use LookupResponse.ProtoReflect.Descriptor instead.
+func (*LookupResponse) Descriptor() ([]byte, []int) {
+	return file_udMessages_proto_rawDescGZIP(), []int{5}
+}
 
-func (m *LookupResponse) GetPubKey() []byte {
-	if m != nil {
-		return m.PubKey
+func (x *LookupResponse) GetPubKey() []byte {
+	if x != nil {
+		return x.PubKey
 	}
 	return nil
 }
 
-func (m *LookupResponse) GetUsername() string {
-	if m != nil {
-		return m.Username
+func (x *LookupResponse) GetUsername() string {
+	if x != nil {
+		return x.Username
 	}
 	return ""
 }
 
-func (m *LookupResponse) GetError() string {
-	if m != nil {
-		return m.Error
+func (x *LookupResponse) GetError() string {
+	if x != nil {
+		return x.Error
 	}
 	return ""
 }
 
-func init() {
-	proto.RegisterType((*HashFact)(nil), "parse.HashFact")
-	proto.RegisterType((*Contact)(nil), "parse.Contact")
-	proto.RegisterType((*SearchSend)(nil), "parse.SearchSend")
-	proto.RegisterType((*SearchResponse)(nil), "parse.SearchResponse")
-	proto.RegisterType((*LookupSend)(nil), "parse.LookupSend")
-	proto.RegisterType((*LookupResponse)(nil), "parse.LookupResponse")
-}
-
-func init() {
-	proto.RegisterFile("udMessages.proto", fileDescriptor_9e0cfdc16fb09bb6)
-}
-
-var fileDescriptor_9e0cfdc16fb09bb6 = []byte{
-	// 283 bytes of a gzipped FileDescriptorProto
-	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x91, 0x41, 0x4b, 0xc3, 0x40,
-	0x10, 0x85, 0xd9, 0x36, 0xad, 0xe9, 0x58, 0xa2, 0x2c, 0x22, 0xc1, 0x53, 0x58, 0x3d, 0x04, 0xc1,
-	0x80, 0xf5, 0x1f, 0xa8, 0x88, 0xa2, 0x5e, 0xb6, 0xb7, 0xde, 0xb6, 0xc9, 0xd8, 0x88, 0x98, 0x5d,
-	0x76, 0x36, 0x87, 0xde, 0xfd, 0xe1, 0x92, 0xcd, 0x9a, 0x82, 0xb4, 0xb7, 0x79, 0x33, 0xf3, 0xb1,
-	0x6f, 0xde, 0xc2, 0x69, 0x5b, 0xbd, 0x23, 0x91, 0xda, 0x20, 0x15, 0xc6, 0x6a, 0xa7, 0xf9, 0xc4,
-	0x28, 0x4b, 0x28, 0x16, 0x10, 0x3f, 0x2b, 0xaa, 0x9f, 0x54, 0xe9, 0x38, 0x87, 0xa8, 0x56, 0x54,
-	0xa7, 0x2c, 0x63, 0xf9, 0x5c, 0xfa, 0xba, 0xeb, 0xb9, 0xad, 0xc1, 0x74, 0x94, 0xb1, 0x7c, 0x22,
-	0x7d, 0x2d, 0x7e, 0x18, 0x1c, 0x3d, 0xe8, 0xc6, 0x75, 0xcc, 0x39, 0x4c, 0x5b, 0x42, 0xfb, 0xf2,
-	0x18, 0xa8, 0xa0, 0xba, 0xbe, 0x69, 0xd7, 0xaf, 0xb8, 0xf5, 0xe4, 0x5c, 0x06, 0xc5, 0x2f, 0x20,
-	0xee, 0x36, 0x1a, 0xf5, 0x8d, 0xe9, 0x38, 0x63, 0xf9, 0x4c, 0x0e, 0x9a, 0xdf, 0xc0, 0xcc, 0xd9,
-	0xcf, 0x4d, 0xe7, 0x85, 0xd2, 0x28, 0x1b, 0xe7, 0xc7, 0x8b, 0x93, 0xc2, 0xdb, 0x2c, 0xfe, 0x3c,
-	0xca, 0xdd, 0x86, 0xb8, 0x05, 0x58, 0xa2, 0xb2, 0x65, 0xbd, 0xc4, 0xa6, 0xe2, 0x97, 0x10, 0x7d,
-	0xa8, 0xd2, 0xa5, 0x6c, 0x3f, 0xe7, 0x87, 0x42, 0x42, 0xd2, 0x23, 0x12, 0xc9, 0xe8, 0x86, 0x90,
-	0x5f, 0x43, 0x5c, 0xf6, 0xa7, 0x50, 0x40, 0x93, 0x80, 0x86, 0x0b, 0xe5, 0x30, 0xe7, 0x67, 0x30,
-	0x41, 0x6b, 0xb5, 0x0d, 0xc6, 0x7b, 0x21, 0xae, 0x00, 0xde, 0xb4, 0xfe, 0x6a, 0x8d, 0xb7, 0x71,
-	0x20, 0x0f, 0xb1, 0x82, 0xa4, 0xdf, 0x1a, 0x5e, 0xde, 0x25, 0xc4, 0x0e, 0x26, 0x34, 0xfa, 0x97,
-	0xd0, 0x5e, 0x07, 0xf7, 0xd1, 0x6a, 0xd4, 0x56, 0xeb, 0xa9, 0xff, 0xd7, 0xbb, 0xdf, 0x00, 0x00,
-	0x00, 0xff, 0xff, 0x5a, 0xee, 0x38, 0xba, 0xeb, 0x01, 0x00, 0x00,
+var File_udMessages_proto protoreflect.FileDescriptor
+
+var file_udMessages_proto_rawDesc = []byte{
+	0x0a, 0x10, 0x75, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f,
+	0x74, 0x6f, 0x12, 0x02, 0x75, 0x64, 0x22, 0x32, 0x0a, 0x08, 0x48, 0x61, 0x73, 0x68, 0x46, 0x61,
+	0x63, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c,
+	0x52, 0x04, 0x68, 0x61, 0x73, 0x68, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02,
+	0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0x81, 0x01, 0x0a, 0x07, 0x43,
+	0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44,
+	0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x12, 0x16,
+	0x0a, 0x06, 0x70, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06,
+	0x70, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61,
+	0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61,
+	0x6d, 0x65, 0x12, 0x2a, 0x0a, 0x09, 0x74, 0x72, 0x69, 0x67, 0x46, 0x61, 0x63, 0x74, 0x73, 0x18,
+	0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x75, 0x64, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x46,
+	0x61, 0x63, 0x74, 0x52, 0x09, 0x74, 0x72, 0x69, 0x67, 0x46, 0x61, 0x63, 0x74, 0x73, 0x22, 0x2e,
+	0x0a, 0x0a, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x53, 0x65, 0x6e, 0x64, 0x12, 0x20, 0x0a, 0x04,
+	0x66, 0x61, 0x63, 0x74, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x75, 0x64, 0x2e,
+	0x48, 0x61, 0x73, 0x68, 0x46, 0x61, 0x63, 0x74, 0x52, 0x04, 0x66, 0x61, 0x63, 0x74, 0x22, 0x4f,
+	0x0a, 0x0e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
+	0x12, 0x27, 0x0a, 0x08, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03,
+	0x28, 0x0b, 0x32, 0x0b, 0x2e, 0x75, 0x64, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x52,
+	0x08, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72,
+	0x6f, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22,
+	0x24, 0x0a, 0x0a, 0x4c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x53, 0x65, 0x6e, 0x64, 0x12, 0x16, 0x0a,
+	0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x75,
+	0x73, 0x65, 0x72, 0x49, 0x44, 0x22, 0x5a, 0x0a, 0x0e, 0x4c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x52,
+	0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x75, 0x62, 0x4b, 0x65,
+	0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x70, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x12,
+	0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28,
+	0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x65,
+	0x72, 0x72, 0x6f, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f,
+	0x72, 0x42, 0x1e, 0x5a, 0x1c, 0x67, 0x69, 0x74, 0x6c, 0x61, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f,
+	0x65, 0x6c, 0x69, 0x78, 0x78, 0x69, 0x72, 0x2f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x2f, 0x75,
+	0x64, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+}
+
+var (
+	file_udMessages_proto_rawDescOnce sync.Once
+	file_udMessages_proto_rawDescData = file_udMessages_proto_rawDesc
+)
+
+func file_udMessages_proto_rawDescGZIP() []byte {
+	file_udMessages_proto_rawDescOnce.Do(func() {
+		file_udMessages_proto_rawDescData = protoimpl.X.CompressGZIP(file_udMessages_proto_rawDescData)
+	})
+	return file_udMessages_proto_rawDescData
+}
+
+var file_udMessages_proto_msgTypes = make([]protoimpl.MessageInfo, 6)
+var file_udMessages_proto_goTypes = []interface{}{
+	(*HashFact)(nil),       // 0: ud.HashFact
+	(*Contact)(nil),        // 1: ud.Contact
+	(*SearchSend)(nil),     // 2: ud.SearchSend
+	(*SearchResponse)(nil), // 3: ud.SearchResponse
+	(*LookupSend)(nil),     // 4: ud.LookupSend
+	(*LookupResponse)(nil), // 5: ud.LookupResponse
+}
+var file_udMessages_proto_depIdxs = []int32{
+	0, // 0: ud.Contact.trigFacts:type_name -> ud.HashFact
+	0, // 1: ud.SearchSend.fact:type_name -> ud.HashFact
+	1, // 2: ud.SearchResponse.contacts:type_name -> ud.Contact
+	3, // [3:3] is the sub-list for method output_type
+	3, // [3:3] is the sub-list for method input_type
+	3, // [3:3] is the sub-list for extension type_name
+	3, // [3:3] is the sub-list for extension extendee
+	0, // [0:3] is the sub-list for field type_name
+}
+
+func init() { file_udMessages_proto_init() }
+func file_udMessages_proto_init() {
+	if File_udMessages_proto != nil {
+		return
+	}
+	if !protoimpl.UnsafeEnabled {
+		file_udMessages_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*HashFact); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_udMessages_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*Contact); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_udMessages_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*SearchSend); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_udMessages_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*SearchResponse); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_udMessages_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*LookupSend); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_udMessages_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*LookupResponse); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+	}
+	type x struct{}
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+			RawDescriptor: file_udMessages_proto_rawDesc,
+			NumEnums:      0,
+			NumMessages:   6,
+			NumExtensions: 0,
+			NumServices:   0,
+		},
+		GoTypes:           file_udMessages_proto_goTypes,
+		DependencyIndexes: file_udMessages_proto_depIdxs,
+		MessageInfos:      file_udMessages_proto_msgTypes,
+	}.Build()
+	File_udMessages_proto = out.File
+	file_udMessages_proto_rawDesc = nil
+	file_udMessages_proto_goTypes = nil
+	file_udMessages_proto_depIdxs = nil
 }
diff --git a/ud/udMessages.proto b/ud/udMessages.proto
index e6905f8359be96a7f331561495d44b20c7e1ab17..e80f56242b6efd85613dcaa1fff760de422b4df6 100644
--- a/ud/udMessages.proto
+++ b/ud/udMessages.proto
@@ -1,16 +1,15 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
-
-// Call ./generate.sh to generate the protocol buffer code
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 syntax = "proto3";
 
-package parse;
-option go_package = "ud";
+package ud;
+
+option go_package = "gitlab.com/elixxir/client/ud";
 
 // Contains the Hash and its Type
 message HashFact {
diff --git a/ud/utils_test.go b/ud/utils_test.go
index 8a1fb7f826ddea93ebbaca272260a018eedef4d3..23de7e4c9eaa26c167f55eeaae452f9e48850e27 100644
--- a/ud/utils_test.go
+++ b/ud/utils_test.go
@@ -1,8 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
+// Copyright © 2022 xx foundation                                             //
 //                                                                            //
 // Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package ud
diff --git a/xxdk/backup.go b/xxdk/backup.go
index f6bbf690545e94ac15fc04670cf0cd02af9101da..301bb48ba0c64368ad4fba0b64b7777f7dccb1d1 100644
--- a/xxdk/backup.go
+++ b/xxdk/backup.go
@@ -1,7 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2022 Privategrity Corporation                                   /
-//                                                                             /
-// All rights reserved.                                                        /
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package xxdk
diff --git a/xxdk/cmix.go b/xxdk/cmix.go
index 539c2610d55f23f3b26ed7aad70e0f563148cc39..a2b8b8b9ad3c6e7cc77c6eb325fabba17084cff0 100644
--- a/xxdk/cmix.go
+++ b/xxdk/cmix.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package xxdk
 
@@ -340,29 +340,28 @@ func (c *Cmix) GetErrorsChannel() <-chan interfaces.ClientError {
 // they are stopped if there is no internet access.
 //
 // Threads Started:
-//   - Network Follower (/network/follow.go)
-//   	tracks the network events and hands them off to workers for handling.
-//   - Historical Round Retrieval (/network/rounds/historical.go)
-// 		retrieves data about rounds that are too old to be stored by the client.
-//	 - Message Retrieval Worker Group (/network/rounds/retrieve.go)
-//		requests all messages in a given round from the gateway of the last
-//		nodes.
-//	 - Message Handling Worker Group (/network/message/handle.go)
-//		decrypts and partitions messages when signals via the Switchboard.
-//	 - Health Tracker (/network/health),
-//		via the network instance, tracks the state of the network.
-//	 - Garbled Messages (/network/message/garbled.go)
-//		can be signaled to check all recent messages that could be decoded. It
-//		uses a message store on disk for persistence.
-//	 - Critical Messages (/network/message/critical.go)
-//		ensures all protocol layer mandatory messages are sent. It uses a
-//		message store on disk for persistence.
-//	 - KeyExchange Trigger (/keyExchange/trigger.go)
-//		responds to sent rekeys and executes them.
-//   - KeyExchange Confirm (/keyExchange/confirm.go)
-//		responds to confirmations of successful rekey operations.
-//   - Auth Callback (/auth/callback.go)
-//      handles both auth confirm and requests.
+//  - Network Follower (/network/follow.go)
+//    tracks the network events and hands them off to workers for handling.
+//  - Historical Round Retrieval (/network/rounds/historical.go)
+//    retrieves data about rounds that are too old to be stored by the client.
+//  - Message Retrieval Worker Group (/network/rounds/retrieve.go)
+//	  requests all messages in a given round from the gateway of the last nodes.
+//  - Message Handling Worker Group (/network/message/handle.go)
+//	  decrypts and partitions messages when signals via the Switchboard.
+//	- Health Tracker (/network/health),
+//	  via the network instance, tracks the state of the network.
+//  - Garbled Messages (/network/message/garbled.go)
+//	  can be signaled to check all recent messages that could be decoded. It
+//	  uses a message store on disk for persistence.
+//	- Critical Messages (/network/message/critical.go)
+//	  ensures all protocol layer mandatory messages are sent. It uses a message
+//	  store on disk for persistence.
+//	- KeyExchange Trigger (/keyExchange/trigger.go)
+//	  responds to sent rekeys and executes them.
+//  - KeyExchange Confirm (/keyExchange/confirm.go)
+//	  responds to confirmations of successful rekey operations.
+//  - Auth Callback (/auth/callback.go)
+//    handles both auth confirm and requests.
 func (c *Cmix) StartNetworkFollower(timeout time.Duration) error {
 	jww.INFO.Printf(
 		"StartNetworkFollower() \n\tTransmissionID: %s \n\tReceptionID: %s",
@@ -375,7 +374,7 @@ func (c *Cmix) StartNetworkFollower(timeout time.Duration) error {
 // an error if the follower is in the wrong state to stop or if it fails to stop
 // it.
 //
-// if the network follower is running and this fails, the client object will
+// If the network follower is running and this fails, the client object will
 // most likely be in an unrecoverable state and need to be trashed.
 func (c *Cmix) StopNetworkFollower() error {
 	jww.INFO.Printf("StopNetworkFollower()")
@@ -398,6 +397,13 @@ func (c *Cmix) HasRunningProcessies() bool {
 	return !c.followerServices.stoppable.IsStopped()
 }
 
+// GetRunningProcesses returns the names of all running processes at the time
+// of this call. Note that this list may change and is subject to race
+// conditions if multiple threads are in the process of starting or stopping.
+func (c *Cmix) GetRunningProcesses() []string {
+	return c.followerServices.stoppable.GetRunningProcesses()
+}
+
 // GetRoundEvents registers a callback for round events.
 func (c *Cmix) GetRoundEvents() interfaces.RoundEvents {
 	jww.INFO.Printf("GetRoundEvents()")
diff --git a/xxdk/compress_test.go b/xxdk/compress_test.go
index 3361115fb8dca117c27e94dfa5dff4a6854955ad..abc64cc52fcfbf73ff9bb7e64f08fd6efa342240 100644
--- a/xxdk/compress_test.go
+++ b/xxdk/compress_test.go
@@ -1,7 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2022 Privategrity Corporation                                   /
-//                                                                             /
-// All rights reserved.                                                        /
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package xxdk
diff --git a/xxdk/e2e.go b/xxdk/e2e.go
index 4c2b9e22ca2e800e77489f69690092e13f6db6bc..a137abca793ecb00267571fc6a4ade03d374a1e3 100644
--- a/xxdk/e2e.go
+++ b/xxdk/e2e.go
@@ -1,7 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2022 Privategrity Corporation                                   /
-//                                                                             /
-// All rights reserved.                                                        /
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package xxdk
@@ -102,7 +103,7 @@ func loginLegacy(net *Cmix, callbacks AuthCallbacks,
 		return nil, err
 	}
 
-	rsaKey, err := identity.GetRSAPrivatePem()
+	rsaKey, err := identity.GetRSAPrivateKey()
 	if err != nil {
 		return nil, err
 	}
@@ -116,7 +117,7 @@ func login(net *Cmix, callbacks AuthCallbacks, identity ReceptionIdentity,
 	kv *versioned.KV, params E2EParams) (m *E2e, err error) {
 
 	// Verify the passed-in ReceptionIdentity matches its properties
-	privatePem, err := identity.GetRSAPrivatePem()
+	privatePem, err := identity.GetRSAPrivateKey()
 	if err != nil {
 		return nil, err
 	}
@@ -246,7 +247,7 @@ func (m *E2e) ConstructProtoUserFile() ([]byte, error) {
 
 	transIdentity := m.Cmix.GetTransmissionIdentity()
 	receptionIdentity := m.GetReceptionIdentity()
-	privatePem, err := receptionIdentity.GetRSAPrivatePem()
+	privatePem, err := receptionIdentity.GetRSAPrivateKey()
 	if err != nil {
 		return nil, err
 	}
diff --git a/xxdk/event.go b/xxdk/event.go
index d65f88c3519aa5ec8b4c5c832e95192180a84bf9..5eccd2d479e940a15c22437938d1e14d5be19d8c 100644
--- a/xxdk/event.go
+++ b/xxdk/event.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package xxdk
 
 import (
diff --git a/xxdk/identity.go b/xxdk/identity.go
index 9d646785fd71c713398036fd4dc8ae66ecbbc447..d0dee696806b356350ce9a6a7c095e3099ace67e 100644
--- a/xxdk/identity.go
+++ b/xxdk/identity.go
@@ -1,7 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2022 Privategrity Corporation                                   /
-//                                                                             /
-// All rights reserved.                                                        /
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package xxdk
@@ -80,8 +81,8 @@ func (r ReceptionIdentity) GetDHKeyPrivate() (*cyclic.Int, error) {
 	return dhKeyPriv, err
 }
 
-// GetRSAPrivatePem returns the RSAPrivatePem.
-func (r ReceptionIdentity) GetRSAPrivatePem() (*rsa.PrivateKey, error) {
+// GetRSAPrivateKey returns the RSAPrivatePem.
+func (r ReceptionIdentity) GetRSAPrivateKey() (*rsa.PrivateKey, error) {
 	return rsa.LoadPrivateKeyFromPem(r.RSAPrivatePem)
 }
 
diff --git a/xxdk/mnemonic.go b/xxdk/mnemonic.go
index 3a2e2051b9485d225704c2896caa6da6319b5dc0..eee9abb936e3a630abb731c163638023045e9e74 100644
--- a/xxdk/mnemonic.go
+++ b/xxdk/mnemonic.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package xxdk
 
diff --git a/xxdk/mnemonic_test.go b/xxdk/mnemonic_test.go
index 326e16dc22f36ee6b6d9e91ba189fba19cb5e5cd..d247fc2f393e06cd1a9f0710310bdc6076ef2508 100644
--- a/xxdk/mnemonic_test.go
+++ b/xxdk/mnemonic_test.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package xxdk
 
diff --git a/xxdk/ndf.go b/xxdk/ndf.go
index 4cdccb6a23e853c68a5987d6f54624e65ae0dba9..6c0009cf6c7062ecd570c4590bd1043394b7915e 100644
--- a/xxdk/ndf.go
+++ b/xxdk/ndf.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package xxdk
 
diff --git a/xxdk/notifications.go b/xxdk/notifications.go
index 17cfb113826b6caa3e2741919abbd455cfde5eb7..f5a9ce96b3cb34765aad2dd2311f0bfec59ded95 100644
--- a/xxdk/notifications.go
+++ b/xxdk/notifications.go
@@ -1,7 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2022 Privategrity Corporation                                   /
-//                                                                             /
-// All rights reserved.                                                        /
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 package xxdk
diff --git a/xxdk/params.go b/xxdk/params.go
index 3313b265d1e3263140cc0a7672e8c12b26672835..7fe436a2c17eea97dd773fdc0ebadc3ee146917b 100644
--- a/xxdk/params.go
+++ b/xxdk/params.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package xxdk
 
diff --git a/xxdk/params_test.go b/xxdk/params_test.go
index 2386b2c99c9b3a93cac29e1a2bc1d10b9c820c8d..93a6334b6b2de2001afa99704d24058e2ab6ffb5 100644
--- a/xxdk/params_test.go
+++ b/xxdk/params_test.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package xxdk
 
diff --git a/xxdk/permissioning.go b/xxdk/permissioning.go
index e5f4032e24ff5b226e855fb9f3a9bf0fba8d6140..54429182de52454d36de0b93faac8f428af72e82 100644
--- a/xxdk/permissioning.go
+++ b/xxdk/permissioning.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package xxdk
 
diff --git a/xxdk/precan.go b/xxdk/precan.go
index 12e7bee315825fa524ffb1079182395a4870348c..3e1a58256b1d1ed316ab5718d0d5248c71d64d13 100644
--- a/xxdk/precan.go
+++ b/xxdk/precan.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package xxdk
 
diff --git a/xxdk/services.go b/xxdk/services.go
index 104362102a3fd6e35483df7208924c83b0a37d2c..840215dc1d3998ebc301766b6232ebef10384d39 100644
--- a/xxdk/services.go
+++ b/xxdk/services.go
@@ -1,3 +1,10 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package xxdk
 
 import (
diff --git a/xxdk/services_test.go b/xxdk/services_test.go
index 580df8f5ad21ab015c281d4a9e2b4d51d4e6af66..18846b9c0c2d5d7d3ac63b98fa5ab378b691108c 100644
--- a/xxdk/services_test.go
+++ b/xxdk/services_test.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package xxdk
 
diff --git a/xxdk/status.go b/xxdk/status.go
index 92e1475de1d6bd3f43676ab90554dfc5665b524b..6b63a523b069fdd1a9614324a4fcc427fe52fa6c 100644
--- a/xxdk/status.go
+++ b/xxdk/status.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package xxdk
 
diff --git a/xxdk/user.go b/xxdk/user.go
index fbf9d339fe5b39b9cde45fa4231e37724222be49..b9fe69e58d529d76f2623880c0fdcef764a246e2 100644
--- a/xxdk/user.go
+++ b/xxdk/user.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package xxdk
 
diff --git a/xxdk/utils.go b/xxdk/utils.go
index 869d9529d111817805fe424c598c07fe5beb6d59..ccb6e3373274e2669a63238b9a34fdfecf0ea0ec 100644
--- a/xxdk/utils.go
+++ b/xxdk/utils.go
@@ -1,7 +1,8 @@
 ////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2022 Privategrity Corporation                                   /
-//                                                                             /
-// All rights reserved.                                                        /
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
 ////////////////////////////////////////////////////////////////////////////////
 
 // Provides various utility functions for access over the bindings
diff --git a/xxdk/utilsInterfaces_test.go b/xxdk/utilsInterfaces_test.go
index 29317d133e3031c8af10eb945ad6fc726d174c1e..4fbf3852387c7c095934c2fbf65f388cfa046e2f 100644
--- a/xxdk/utilsInterfaces_test.go
+++ b/xxdk/utilsInterfaces_test.go
@@ -1,9 +1,10 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
 package xxdk
 
 import (
@@ -108,13 +109,20 @@ func (t *testNetworkManagerGeneric) AddFingerprint(identity *id.ID, fingerprint
 }
 
 func (t *testNetworkManagerGeneric) Send(*id.ID, format.Fingerprint,
-	message.Service, []byte, []byte, cmix.CMIXParams) (id.Round,
+	message.Service, []byte, []byte, cmix.CMIXParams) (rounds.Round,
 	ephemeral.Id, error) {
-	return id.Round(0), ephemeral.Id{}, nil
+	return rounds.Round{}, ephemeral.Id{}, nil
+}
+
+func (t *testNetworkManagerGeneric) SendWithAssembler(recipient *id.ID, assembler cmix.MessageAssembler,
+	cmixParams cmix.CMIXParams) (rounds.Round, ephemeral.Id, error) {
+
+	return rounds.Round{}, ephemeral.Id{}, nil
 }
+
 func (t *testNetworkManagerGeneric) SendMany(messages []cmix.TargetedCmixMessage,
-	p cmix.CMIXParams) (id.Round, []ephemeral.Id, error) {
-	return 0, []ephemeral.Id{}, nil
+	p cmix.CMIXParams) (rounds.Round, []ephemeral.Id, error) {
+	return rounds.Round{}, []ephemeral.Id{}, nil
 }
 func (t *testNetworkManagerGeneric) GetInstance() *network.Instance {
 	return t.instance
@@ -175,8 +183,7 @@ func (t *testNetworkManagerGeneric) GetIdentity(get *id.ID) (
 	return identity.TrackedID{}, nil
 }
 func (t *testNetworkManagerGeneric) GetRoundResults(timeout time.Duration,
-	roundCallback cmix.RoundEventCallback, roundList ...id.Round) error {
-	return nil
+	roundCallback cmix.RoundEventCallback, roundList ...id.Round) {
 }
 func (t *testNetworkManagerGeneric) HasNode(nid *id.ID) bool { return false }
 func (t *testNetworkManagerGeneric) IsHealthy() bool         { return true }
diff --git a/xxdk/utils_test.go b/xxdk/utils_test.go
index f5ca8f965078da696a3aadbe0dd1578595339a98..40098e5beb2abf5b05bc1556e232e373a032c1dd 100644
--- a/xxdk/utils_test.go
+++ b/xxdk/utils_test.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package xxdk
 
diff --git a/xxdk/version_vars.go b/xxdk/version_vars.go
index 1107c2c1141673d1bbe3b35aafb509177bac1cb8..61bd87da81f93ce196ac84a628a11107357ecb24 100644
--- a/xxdk/version_vars.go
+++ b/xxdk/version_vars.go
@@ -1,10 +1,10 @@
 // Code generated by go generate; DO NOT EDIT.
 // This file was generated by robots at
-// 2022-08-03 11:29:24.178017 -0500 CDT m=+0.037661773
+// 2022-09-15 10:52:12.1953796 -0700 PDT m=+0.451573601
 
 package xxdk
 
-const GITVERSION = `97f2ad74 Merge branch 'feature/roundpickup' into 'release'`
+const GITVERSION = `55b66f6b Update proto files`
 const SEMVER = "4.2.0"
 const DEPENDENCIES = `module gitlab.com/elixxir/client
 
@@ -16,17 +16,18 @@ require (
 	github.com/golang/protobuf v1.5.2
 	github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646
 	github.com/pkg/errors v0.9.1
+	github.com/pkg/profile v1.6.0
 	github.com/spf13/cobra v1.5.0
 	github.com/spf13/jwalterweatherman v1.1.0
 	github.com/spf13/viper v1.12.0
 	gitlab.com/elixxir/bloomfilter v0.0.0-20211222005329-7d931ceead6f
-	gitlab.com/elixxir/comms v0.0.4-0.20220603231314-e47e4af13326
-	gitlab.com/elixxir/crypto v0.0.7-0.20220606201132-c370d5039cea
-	gitlab.com/elixxir/ekv v0.1.7
-	gitlab.com/elixxir/primitives v0.0.3-0.20220606195757-40f7a589347f
-	gitlab.com/xx_network/comms v0.0.4-0.20220630163702-f3d372ef6acd
-	gitlab.com/xx_network/crypto v0.0.5-0.20220729193517-1e5e96f39f6e
-	gitlab.com/xx_network/primitives v0.0.4-0.20220712193914-aebd8544396e
+	gitlab.com/elixxir/comms v0.0.4-0.20220914220142-601071b77d78
+	gitlab.com/elixxir/crypto v0.0.7-0.20220901215826-1ceaeb59081f
+	gitlab.com/elixxir/ekv v0.2.1
+	gitlab.com/elixxir/primitives v0.0.3-0.20220901220638-1acc75fabdc6
+	gitlab.com/xx_network/comms v0.0.4-0.20220914220351-2e461edbfe48
+	gitlab.com/xx_network/crypto v0.0.5-0.20220902182733-69aad094b487
+	gitlab.com/xx_network/primitives v0.0.4-0.20220902183448-319596e2fec8
 	go.uber.org/ratelimit v0.2.0
 	golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa
 	golang.org/x/net v0.0.0-20220802222814-0bcc04d9c69b
diff --git a/xxmutils/restoreContacts.go b/xxmutils/restoreContacts.go
index 9f43d294e35b7f6d601ba780b93b69bb0966a002..0ee9363130c1d302a822d1509447f52cd5ae1e56 100644
--- a/xxmutils/restoreContacts.go
+++ b/xxmutils/restoreContacts.go
@@ -1,9 +1,9 @@
-///////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                          //
-//                                                                           //
-// Use of this source code is governed by a license that can be found in the //
-// LICENSE file                                                              //
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2022 xx foundation                                             //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file.                                                              //
+////////////////////////////////////////////////////////////////////////////////
 
 package xxmutils