diff --git a/api/authenticatedChannel.go b/api/authenticatedChannel.go
index 8d921698d0687bd93e32ef1ee9ed2f46d68fce57..d1b5aa3ef75e573c9e39c9aaff8001656ef5e476 100644
--- a/api/authenticatedChannel.go
+++ b/api/authenticatedChannel.go
@@ -3,6 +3,7 @@ package api
 import (
 	jww "github.com/spf13/jwalterweatherman"
 	"gitlab.com/elixxir/client/interfaces/contact"
+	"gitlab.com/elixxir/client/storage/e2e"
 )
 
 // CreateAuthenticatedChannel creates a 1-way authenticated channel
@@ -29,3 +30,35 @@ func (c *Client) RegisterAuthRequestCb(cb func(contact contact.Contact,
 	payload []byte)) {
 	jww.INFO.Printf("RegisterAuthRequestCb(...)")
 }
+
+// Create an insecure e2e relationship with a precanned user
+func (c *Client) MakePrecannedAuthenticatedChannel(precannedID uint) contact.Contact {
+
+	precan := c.MakePrecannedContact(precannedID)
+
+	//add the precanned user as a e2e contact
+	sesParam := e2e.GetDefaultSessionParams()
+	c.storage.E2e().AddPartner(precan.ID, precan.DhPubKey, sesParam, sesParam)
+
+	return precan
+}
+
+// Create an insecure e2e contact object for a precanned user
+func (c *Client) MakePrecannedContact(precannedID uint) contact.Contact {
+
+	e2eGrp := c.storage.E2e().GetGroup()
+
+	//get the user definition
+	precanned := createPrecannedUser(precannedID, c.rng.GetStream(),
+		c.storage.Cmix().GetGroup(), e2eGrp)
+
+	//compute their public e2e key
+	partnerPubKey := e2eGrp.ExpG(precanned.E2eDhPrivateKey, e2eGrp.NewInt(1))
+
+	return contact.Contact{
+		ID:             precanned.ID,
+		DhPubKey:       partnerPubKey,
+		OwnershipProof: nil,
+		Facts:          make([]contact.Fact, 0),
+	}
+}
\ No newline at end of file
diff --git a/api/client.go b/api/client.go
index da8603198def8b98bd217b8e7ccfc4543eb9815a..4b8aefc7c23ca78dcd675959b851a3d33a7fb3b9 100644
--- a/api/client.go
+++ b/api/client.go
@@ -56,7 +56,7 @@ type Client struct {
 // 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.
-func NewClient(ndfJSON, storageDir string, password []byte, registrationCode string) (*Client, error) {
+func NewClient(ndfJSON, storageDir string, password []byte, registrationCode string) error {
 	// Use fastRNG for RNG ops (AES fortuna based RNG using system RNG)
 	rngStreamGen := fastRNG.NewStreamGenerator(12, 3, csprng.NewSystemRNG)
 	rngStream := rngStreamGen.GetStream()
@@ -64,7 +64,7 @@ func NewClient(ndfJSON, storageDir string, password []byte, registrationCode str
 	// Parse the NDF
 	def, err := parseNDF(ndfJSON)
 	if err != nil {
-		return nil, err
+		return err
 	}
 	cmixGrp, e2eGrp := decodeGroups(def)
 
@@ -75,7 +75,7 @@ func NewClient(ndfJSON, storageDir string, password []byte, registrationCode str
 	storageSess, err := storage.New(storageDir, passwordStr, protoUser,
 		cmixGrp, e2eGrp, rngStreamGen)
 	if err != nil {
-		return nil, err
+		return err
 	}
 
 	// Save NDF to be used in the future
@@ -87,12 +87,12 @@ func NewClient(ndfJSON, storageDir string, password []byte, registrationCode str
 	//move the registration state to keys generated
 	err = storageSess.ForwardRegistrationStatus(storage.KeyGenComplete)
 	if err != nil {
-		return nil, errors.WithMessage(err, "Failed to denote state "+
+		return errors.WithMessage(err, "Failed to denote state "+
 			"change in session")
 	}
 
-	//execute the rest of the loading as normal
-	return loadClient(storageSess, rngStreamGen)
+	//TODO: close the session
+	return nil
 }
 
 // NewPrecannedClient creates an insecure user with predetermined keys with nodes
@@ -100,7 +100,7 @@ func NewClient(ndfJSON, storageDir string, password []byte, registrationCode str
 // 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.
-func NewPrecannedClient(precannedID uint, defJSON, storageDir string, password []byte) (*Client, error) {
+func NewPrecannedClient(precannedID uint, defJSON, storageDir string, password []byte) error {
 	// Use fastRNG for RNG ops (AES fortuna based RNG using system RNG)
 	rngStreamGen := fastRNG.NewStreamGenerator(12, 3, csprng.NewSystemRNG)
 	rngStream := rngStreamGen.GetStream()
@@ -108,7 +108,7 @@ func NewPrecannedClient(precannedID uint, defJSON, storageDir string, password [
 	// Parse the NDF
 	def, err := parseNDF(defJSON)
 	if err != nil {
-		return nil, err
+		return err
 	}
 	cmixGrp, e2eGrp := decodeGroups(def)
 
@@ -119,7 +119,7 @@ func NewPrecannedClient(precannedID uint, defJSON, storageDir string, password [
 	storageSess, err := storage.New(storageDir, passwordStr, protoUser,
 		cmixGrp, e2eGrp, rngStreamGen)
 	if err != nil {
-		return nil, err
+		return err
 	}
 
 	// Save NDF to be used in the future
@@ -128,12 +128,12 @@ func NewPrecannedClient(precannedID uint, defJSON, storageDir string, password [
 	//move the registration state to keys generated
 	err = storageSess.ForwardRegistrationStatus(storage.KeyGenComplete)
 	if err != nil {
-		return nil, errors.WithMessage(err, "Failed to denote state "+
+		return errors.WithMessage(err, "Failed to denote state "+
 			"change in session")
 	}
 
-	//execute the rest of the loading as normal
-	return loadClient(storageSess, rngStreamGen)
+	//TODO: close the session
+	return nil
 }
 
 // LoadClient initalizes a client object from existing storage.
diff --git a/cmd/root.go b/cmd/root.go
index df02bc00954d7ec5a67d6790c78d9647a983f3dc..ce181ec658c8c3ad2b51f1c3b86c4530dc290267 100644
--- a/cmd/root.go
+++ b/cmd/root.go
@@ -128,7 +128,7 @@ var rootCmd = &cobra.Command{
 		storeDir := viper.GetString("session")
 		regCode := viper.GetString("regcode")
 
-		var client *api.Client
+		//create a new client if none exist
 		if _, err := os.Stat(storeDir); os.IsNotExist(err) {
 			// Load NDF
 			ndfPath := viper.GetString("ndf")
@@ -137,22 +137,23 @@ var rootCmd = &cobra.Command{
 				jww.FATAL.Panicf(err.Error())
 			}
 
-			client, err = api.NewClient(string(ndfJSON), storeDir,
+			err = api.NewClient(string(ndfJSON), storeDir,
 				[]byte(pass), regCode)
 			if err != nil {
 				jww.FATAL.Panicf("%+v", err)
 			}
-		} else {
-			client, err = api.LoadClient(storeDir, []byte(pass))
-			if err != nil {
-				jww.FATAL.Panicf("%+v", err)
-			}
+		}
+
+		//load the client
+		client, err := api.LoadClient(storeDir, []byte(pass))
+		if err != nil {
+			jww.FATAL.Panicf("%+v", err)
 		}
 
 		user := client.GetUser()
 		jww.INFO.Printf("%s", user.ID)
 
-		err := client.StartNetworkFollower()
+		err = client.StartNetworkFollower()
 		if err != nil {
 			jww.FATAL.Panicf("%+v", err)
 		}
diff --git a/interfaces/contact.go b/interfaces/contact.go
index d9890553979d9e8faefbe7fc9a8f74210f2ea229..41f285c73cf26eb7de446942733a3e24de95d203 100644
--- a/interfaces/contact.go
+++ b/interfaces/contact.go
@@ -3,13 +3,18 @@ package interfaces
 type Contact interface {
 	GetID() []byte
 	GetDHPublicKey() []byte
-	AddFact(Fact) Contact
-	NumFacts() int
-	GetFact(int) (Fact, error)
+	GetOwnershipProof() []byte
+	GetFactList() FactList
 	Marshal() ([]byte, error)
 }
 
+type FactList interface {
+	Num() int
+	Get(int) Fact
+	Add(string, int) error
+}
+
 type Fact interface {
 	Get() string
-	GetType() int
+	Type() int
 }
diff --git a/interfaces/contact/contact.go b/interfaces/contact/contact.go
index 145363b192185a8ab8dbaa69219040a0c9a16123..f67175fc8197ed5ed6fc42cfc2a13da22222a4ca 100644
--- a/interfaces/contact/contact.go
+++ b/interfaces/contact/contact.go
@@ -4,7 +4,6 @@ import (
 	"encoding/json"
 	"github.com/pkg/errors"
 	"gitlab.com/elixxir/client/interfaces"
-	"gitlab.com/elixxir/client/interfaces/contact/fact"
 	"gitlab.com/elixxir/crypto/cyclic"
 	"gitlab.com/xx_network/primitives/id"
 )
@@ -13,9 +12,10 @@ import (
 // in go, the structure is meant to be edited directly, the functions are for
 // bindings compatibility
 type Contact struct {
-	ID       *id.ID
-	DhPubKey *cyclic.Int
-	Facts    []fact.Fact
+	ID             *id.ID
+	DhPubKey       *cyclic.Int
+	OwnershipProof []byte
+	Facts          []Fact
 }
 
 // GetID returns the user ID for this user.
@@ -23,32 +23,19 @@ func (c Contact) GetID() []byte {
 	return c.ID.Bytes()
 }
 
-// GetPublicKey returns the publickey bytes for this user.
+// GetDHPublicKey returns the public key associated with the Contact.
 func (c Contact) GetDHPublicKey() []byte {
 	return c.DhPubKey.Bytes()
 }
 
-// Adds a fact to the contact. Because the contact is pass by value, this makes
-// a new copy with the fact
-func (c Contact) AddFact(f interfaces.Fact) interfaces.Contact {
-	fNew := fact.Fact{
-		Fact: f.Get(),
-		T:    fact.Type(f.GetType()),
-	}
-	c.Facts = append(c.Facts, fNew)
-	return c
-}
-
-func (c Contact) NumFacts() int {
-	return len(c.Facts)
+// GetDHPublicKey returns hash of a DH proof of key ownership.
+func (c Contact) GetOwnershipProof() []byte {
+	return c.OwnershipProof
 }
 
-func (c Contact) GetFact(i int) (interfaces.Fact, error) {
-	if i >= len(c.Facts) || i < 0 {
-		return nil, errors.Errorf("Cannot get a a fact at position %v, "+
-			"only %v facts", i, len(c.Facts))
-	}
-	return c.Facts[i], nil
+// Returns a fact list for adding and getting facts to and from the contact
+func (c Contact) GetFactList() interfaces.FactList {
+	return FactList{source: &c}
 }
 
 func (c Contact) Marshal() ([]byte, error) {
diff --git a/interfaces/contact/fact/fact.go b/interfaces/contact/fact.go
similarity index 67%
rename from interfaces/contact/fact/fact.go
rename to interfaces/contact/fact.go
index 9aa96742fcbcc28623939d37d6de088577a7e24f..a5af2ab57b2c537889f640cef4f6c7f414787ba8 100644
--- a/interfaces/contact/fact/fact.go
+++ b/interfaces/contact/fact.go
@@ -1,31 +1,22 @@
-package fact
+package contact
 
 import (
 	"github.com/pkg/errors"
-	"gitlab.com/elixxir/client/interfaces"
 )
 
 type Fact struct {
 	Fact string
-	T    Type
+	T    FactType
 }
 
 func (f Fact) Get() string {
 	return f.Fact
 }
 
-func (f Fact) GetType() int {
+func (f Fact) Type() int {
 	return int(f.T)
 }
 
-func (f Fact) Copy() interfaces.Fact {
-	f2 := Fact{
-		Fact: f.Fact,
-		T:    f.T,
-	}
-	return &f2
-}
-
 // marshal is for transmission for UDB, not a part of the fact interface
 func (f Fact) Marshal() []byte {
 	serial := []byte(f.Fact)
@@ -36,8 +27,8 @@ func (f Fact) Marshal() []byte {
 	return b
 }
 
-func Unmarshal(b []byte) (Fact, error) {
-	t := Type(b[0])
+func UnmarshalFact(b []byte) (Fact, error) {
+	t := FactType(b[0])
 	if !t.IsValid() {
 		return Fact{}, errors.Errorf("Fact is not a valid type: %s", t)
 	}
diff --git a/interfaces/contact/fact/type.go b/interfaces/contact/fact/type.go
deleted file mode 100644
index cc0ff89334bf031db54139d57c006539f54e8bbd..0000000000000000000000000000000000000000
--- a/interfaces/contact/fact/type.go
+++ /dev/null
@@ -1,28 +0,0 @@
-package fact
-
-import "fmt"
-
-type Type uint8
-
-const (
-	Username Type = 0
-	Email    Type = 1
-	Phone    Type = 2
-)
-
-func (t Type) String() string {
-	switch t {
-	case Username:
-		return "Username"
-	case Email:
-		return "Email"
-	case Phone:
-		return "Phone"
-	default:
-		return fmt.Sprintf("Unknown Fact Type: %d", t)
-	}
-}
-
-func (t Type) IsValid() bool {
-	return t == Username || t == Email || t == Phone
-}
diff --git a/interfaces/contact/factList.go b/interfaces/contact/factList.go
new file mode 100644
index 0000000000000000000000000000000000000000..5c39398fc3847d7c126802fda00d274e1737bd7e
--- /dev/null
+++ b/interfaces/contact/factList.go
@@ -0,0 +1,30 @@
+package contact
+
+import (
+	"github.com/pkg/errors"
+	"gitlab.com/elixxir/client/interfaces"
+)
+
+type FactList struct {
+	source *Contact
+}
+
+func (fl FactList) Num() int {
+	return len(fl.source.Facts)
+}
+
+func (fl FactList) Get(i int) interfaces.Fact {
+	return fl.source.Facts[i]
+}
+
+func (fl FactList) Add(fact string, factType int) error {
+	ft := FactType(factType)
+	if !ft.IsValid() {
+		return errors.New("Invalid fact type")
+	}
+	fl.source.Facts = append(fl.source.Facts, Fact{
+		Fact: fact,
+		T:    ft,
+	})
+	return nil
+}
diff --git a/interfaces/contact/type.go b/interfaces/contact/type.go
new file mode 100644
index 0000000000000000000000000000000000000000..1b9bb89892e2394a6aa0f06744ce7c5ce8ee6e44
--- /dev/null
+++ b/interfaces/contact/type.go
@@ -0,0 +1,28 @@
+package contact
+
+import "fmt"
+
+type FactType uint8
+
+const (
+	Username FactType = 0
+	Email    FactType = 1
+	Phone    FactType = 2
+)
+
+func (t FactType) String() string {
+	switch t {
+	case Username:
+		return "Username"
+	case Email:
+		return "Email"
+	case Phone:
+		return "Phone"
+	default:
+		return fmt.Sprintf("Unknown Fact FactType: %d", t)
+	}
+}
+
+func (t FactType) IsValid() bool {
+	return t == Username || t == Email || t == Phone
+}
diff --git a/interfaces/user/user.go b/interfaces/user/user.go
index d84f406b5ca3d7a70fd1b2ac0873728958cc5fef..298e61fc53693f0767291f6853cb7c120506b590 100644
--- a/interfaces/user/user.go
+++ b/interfaces/user/user.go
@@ -64,6 +64,6 @@ func (u User) GetContact() interfaces.Contact {
 	return contact.Contact{
 		ID:       u.ID.DeepCopy(),
 		DhPubKey: u.E2eDhPublicKey,
-		Facts:    nil,
+		Facts:    make([]contact.Fact, 0),
 	}
 }
diff --git a/storage/user/user.go b/storage/user/user.go
index 7abd5f2e2962e4ec84be4d141c53472c27d9b135..8e62c933cc2a741a791c096f80f0696b07ccb32c 100644
--- a/storage/user/user.go
+++ b/storage/user/user.go
@@ -45,4 +45,4 @@ func LoadUser(kv *versioned.KV) (*User, error) {
 
 func (u *User) GetCryptographicIdentity() *CryptographicIdentity {
 	return u.ci
-}
+}
\ No newline at end of file