Repository: hyperledger/firefly (go)

Issue:
Can submit transfers/approvals to the wrong connector
Transfers and approvals are tied to a pool, and the pool is tied to a connector. But currently the input for transfers/approvals requires you to specify both "pool" and "connector".

"connector" should not be required. It should be looked up from the associated pool.

Currently you can cause transfers to be submitted to the wrong token connector if you have multiple connectors.

Pull request:
Omit "connector" from token transfer/approval inputs
This should always be inferred from the token pool.

Fixes #768

Patch:
diff --git a/docs/swagger/swagger.yaml b/docs/swagger/swagger.yaml
index 8f6002c66..a4729199c 100644
--- a/docs/swagger/swagger.yaml
+++ b/docs/swagger/swagger.yaml
@@ -10431,11 +10431,6 @@ paths:
                     of the approval.  See your chosen token connector documentation
                     for details
                   type: object
-                connector:
-                  description: The name of the token connector, as specified in the
-                    FireFly core configuration file. Required on input when there
-                    are more than one token connectors configured
-                  type: string
                 info:
                   additionalProperties:
                     description: Token connector specific information about the approval
@@ -10821,11 +10816,6 @@ paths:
                     For example, with 18 decimals a fractional balance of 10.234 will
                     be specified as 10,234,000,000,000,000,000
                   type: string
-                connector:
-                  description: The name of the token connector, as specified in the
-                    FireFly core configuration file. Required on input when there
-                    are more than one token connectors configured
-                  type: string
                 from:
                   description: The source account for the transfer. On input defaults
                     to the value of 'key'
@@ -11245,11 +11235,6 @@ paths:
                     For example, with 18 decimals a fractional balance of 10.234 will
                     be specified as 10,234,000,000,000,000,000
                   type: string
-                connector:
-                  description: The name of the token connector, as specified in the
-                    FireFly core configuration file. Required on input when there
-                    are more than one token connectors configured
-                  type: string
                 key:
                   description: The blockchain signing key for the transfer. On input
                     defaults to the first signing key of the organization that operates
@@ -12451,11 +12436,6 @@ paths:
                     For example, with 18 decimals a fractional balance of 10.234 will
                     be specified as 10,234,000,000,000,000,000
                   type: string
-                connector:
-                  description: The name of the token connector, as specified in the
-                    FireFly core configuration file. Required on input when there
-                    are more than one token connectors configured
-                  type: string
                 from:
                   description: The source account for the transfer. On input defaults
                     to the value of 'key'
diff --git a/internal/apiserver/route_get_token_connectors.go b/internal/apiserver/route_get_token_connectors.go
index f3abd135f..83806bf44 100644
--- a/internal/apiserver/route_get_token_connectors.go
+++ b/internal/apiserver/route_get_token_connectors.go
@@ -39,6 +39,6 @@ var getTokenConnectors = &oapispec.Route{
 	JSONOutputValue: func() interface{} { return []*fftypes.TokenConnector{} },
 	JSONOutputCodes: []int{http.StatusOK},
 	JSONHandler: func(r *oapispec.APIRequest) (output interface{}, err error) {
-		return getOr(r.Ctx).Assets().GetTokenConnectors(r.Ctx, r.PP["ns"])
+		return getOr(r.Ctx).Assets().GetTokenConnectors(r.Ctx, r.PP["ns"]), nil
 	},
 }
diff --git a/internal/assets/manager.go b/internal/assets/manager.go
index 18fd79b9d..6e18b11a6 100644
--- a/internal/assets/manager.go
+++ b/internal/assets/manager.go
@@ -58,7 +58,7 @@ type Manager interface {
 	BurnTokens(ctx context.Context, ns string, transfer *fftypes.TokenTransferInput, waitConfirm bool) (*fftypes.TokenTransfer, error)
 	TransferTokens(ctx context.Context, ns string, transfer *fftypes.TokenTransferInput, waitConfirm bool) (*fftypes.TokenTransfer, error)
 
-	GetTokenConnectors(ctx context.Context, ns string) ([]*fftypes.TokenConnector, error)
+	GetTokenConnectors(ctx context.Context, ns string) []*fftypes.TokenConnector
 
 	NewApproval(ns string, approve *fftypes.TokenApprovalInput) sysmessaging.MessageSender
 	TokenApproval(ctx context.Context, ns string, approval *fftypes.TokenApprovalInput, waitConfirm bool) (*fftypes.TokenApproval, error)
@@ -140,11 +140,7 @@ func (am *assetManager) GetTokenAccountPools(ctx context.Context, ns, key string
 	return am.database.GetTokenAccountPools(ctx, key, am.scopeNS(ns, filter))
 }
 
-func (am *assetManager) GetTokenConnectors(ctx context.Context, ns string) ([]*fftypes.TokenConnector, error) {
-	if err := fftypes.ValidateFFNameField(ctx, ns, "namespace"); err != nil {
-		return nil, err
-	}
-
+func (am *assetManager) GetTokenConnectors(ctx context.Context, ns string) []*fftypes.TokenConnector {
 	connectors := []*fftypes.TokenConnector{}
 	for token := range am.tokens {
 		connectors = append(
@@ -154,30 +150,26 @@ func (am *assetManager) GetTokenConnectors(ctx context.Context, ns string) ([]*f
 			},
 		)
 	}
-
-	return connectors, nil
+	return connectors
 }
 
-func (am *assetManager) getTokenConnectorName(ctx context.Context, ns string) (string, error) {
-	tokenConnectors, err := am.GetTokenConnectors(ctx, ns)
-	if err != nil {
-		return "", err
-	}
+func (am *assetManager) getDefaultTokenConnector(ctx context.Context, ns string) (string, error) {
+	tokenConnectors := am.GetTokenConnectors(ctx, ns)
 	if len(tokenConnectors) != 1 {
 		return "", i18n.NewError(ctx, coremsgs.MsgFieldNotSpecified, "connector")
 	}
 	return tokenConnectors[0].Name, nil
 }
 
-func (am *assetManager) getTokenPoolName(ctx context.Context, ns string) (string, error) {
+func (am *assetManager) getDefaultTokenPool(ctx context.Context, ns string) (*fftypes.TokenPool, error) {
 	f := database.TokenPoolQueryFactory.NewFilter(ctx).And()
 	f.Limit(1).Count(true)
 	tokenPools, fr, err := am.GetTokenPools(ctx, ns, f)
 	if err != nil {
-		return "", err
+		return nil, err
 	}
 	if *fr.TotalCount != 1 {
-		return "", i18n.NewError(ctx, coremsgs.MsgFieldNotSpecified, "pool")
+		return nil, i18n.NewError(ctx, coremsgs.MsgFieldNotSpecified, "pool")
 	}
-	return tokenPools[0].Name, nil
+	return tokenPools[0], nil
 }
diff --git a/internal/assets/token_approval.go b/internal/assets/token_approval.go
index dc7a30793..9c47a2a23 100644
--- a/internal/assets/token_approval.go
+++ b/internal/assets/token_approval.go
@@ -64,10 +64,6 @@ func (am *assetManager) NewApproval(ns string, approval *fftypes.TokenApprovalIn
 }
 
 func (am *assetManager) TokenApproval(ctx context.Context, ns string, approval *fftypes.TokenApprovalInput, waitConfirm bool) (out *fftypes.TokenApproval, err error) {
-	if err := am.validateApproval(ctx, ns, approval); err != nil {
-		return nil, err
-	}
-
 	sender := am.NewApproval(ns, approval)
 	if waitConfirm {
 		err = sender.SendAndWait(ctx)
@@ -77,7 +73,7 @@ func (am *assetManager) TokenApproval(ctx context.Context, ns string, approval *
 	return &approval.TokenApproval, err
 }
 
-func (s *approveSender) sendInternal(ctx context.Context, method sendMethod) error {
+func (s *approveSender) sendInternal(ctx context.Context, method sendMethod) (err error) {
 	if method == methodSendAndWait {
 		out, err := s.mgr.syncasync.WaitForTokenApproval(ctx, s.namespace, s.approval.LocalID, s.Send)
 		if out != nil {
@@ -86,34 +82,29 @@ func (s *approveSender) sendInternal(ctx context.Context, method sendMethod) err
 		return err
 	}
 
-	plugin, err := s.mgr.selectTokenPlugin(ctx, s.approval.Connector)
-	if err != nil {
-		return err
-	}
-
-	if method == methodPrepare {
-		return nil
-	}
-
-	var pool *fftypes.TokenPool
 	var op *fftypes.Operation
+	var pool *fftypes.TokenPool
 	err = s.mgr.database.RunAsGroup(ctx, func(ctx context.Context) (err error) {
-		pool, err = s.mgr.GetTokenPoolByNameOrID(ctx, s.namespace, s.approval.Pool)
+		pool, err = s.mgr.validateApproval(ctx, s.namespace, s.approval)
 		if err != nil {
 			return err
 		}
-		if pool.State != fftypes.TokenPoolStateConfirmed {
-			return i18n.NewError(ctx, coremsgs.MsgTokenPoolNotConfirmed)
+
+		plugin, err := s.mgr.selectTokenPlugin(ctx, s.approval.Connector)
+		if err != nil {
+			return err
+		}
+
+		if method == methodPrepare {
+			return nil
 		}
 
 		txid, err := s.mgr.txHelper.SubmitNewTransaction(ctx, s.namespace, fftypes.TransactionTypeTokenApproval)
 		if err != nil {
 			return err
 		}
-
 		s.approval.TX.ID = txid
 		s.approval.TX.Type = fftypes.TransactionTypeTokenApproval
-		s.approval.TokenApproval.Pool = pool.ID
 
 		op = fftypes.NewOperation(
 			plugin,
@@ -127,27 +118,32 @@ func (s *approveSender) sendInternal(ctx context.Context, method sendMethod) err
 	})
 	if err != nil {
 		return err
+	} else if method == methodPrepare {
+		return nil
 	}
 
 	_, err = s.mgr.operations.RunOperation(ctx, opApproval(op, pool, &s.approval.TokenApproval))
 	return err
 }
 
-func (am *assetManager) validateApproval(ctx context.Context, ns string, approval *fftypes.TokenApprovalInput) (err error) {
-	if approval.Connector == "" {
-		connector, err := am.getTokenConnectorName(ctx, ns)
+func (am *assetManager) validateApproval(ctx context.Context, ns string, approval *fftypes.TokenApprovalInput) (pool *fftypes.TokenPool, err error) {
+	if approval.Pool == "" {
+		pool, err = am.getDefaultTokenPool(ctx, ns)
 		if err != nil {
-			return err
+			return nil, err
 		}
-		approval.Connector = connector
-	}
-	if approval.Pool == "" {
-		pool, err := am.getTokenPoolName(ctx, ns)
+	} else {
+		pool, err = am.GetTokenPoolByNameOrID(ctx, ns, approval.Pool)
 		if err != nil {
-			return err
+			return nil, err
 		}
-		approval.Pool = pool
+	}
+	approval.TokenApproval.Pool = pool.ID
+	approval.TokenApproval.Connector = pool.Connector
+
+	if pool.State != fftypes.TokenPoolStateConfirmed {
+		return nil, i18n.NewError(ctx, coremsgs.MsgTokenPoolNotConfirmed)
 	}
 	approval.Key, err = am.identity.NormalizeSigningKey(ctx, approval.Key, am.keyNormalization)
-	return err
+	return pool, err
 }
diff --git a/internal/assets/token_pool.go b/internal/assets/token_pool.go
index 8018b0f08..bc3a44a16 100644
--- a/internal/assets/token_pool.go
+++ b/internal/assets/token_pool.go
@@ -43,7 +43,7 @@ func (am *assetManager) CreateTokenPool(ctx context.Context, ns string, pool *ff
 	pool.Namespace = ns
 
 	if pool.Connector == "" {
-		connector, err := am.getTokenConnectorName(ctx, ns)
+		connector, err := am.getDefaultTokenConnector(ctx, ns)
 		if err != nil {
 			return nil, err
 		}
diff --git a/internal/assets/token_transfer.go b/internal/assets/token_transfer.go
index 6a684834b..a5338ba2a 100644
--- a/internal/assets/token_transfer.go
+++ b/internal/assets/token_transfer.go
@@ -87,23 +87,26 @@ func (s *transferSender) setDefaults() {
 	s.transfer.LocalID = fftypes.NewUUID()
 }
 
-func (am *assetManager) validateTransfer(ctx context.Context, ns string, transfer *fftypes.TokenTransferInput) (err error) {
-	if transfer.Connector == "" {
-		connector, err := am.getTokenConnectorName(ctx, ns)
+func (am *assetManager) validateTransfer(ctx context.Context, ns string, transfer *fftypes.TokenTransferInput) (pool *fftypes.TokenPool, err error) {
+	if transfer.Pool == "" {
+		pool, err = am.getDefaultTokenPool(ctx, ns)
 		if err != nil {
-			return err
+			return nil, err
 		}
-		transfer.Connector = connector
-	}
-	if transfer.Pool == "" {
-		pool, err := am.getTokenPoolName(ctx, ns)
+	} else {
+		pool, err = am.GetTokenPoolByNameOrID(ctx, ns, transfer.Pool)
 		if err != nil {
-			return err
+			return nil, err
 		}
-		transfer.Pool = pool
+	}
+	transfer.TokenTransfer.Pool = pool.ID
+	transfer.TokenTransfer.Connector = pool.Connector
+
+	if pool.State != fftypes.TokenPoolStateConfirmed {
+		return nil, i18n.NewError(ctx, coremsgs.MsgTokenPoolNotConfirmed)
 	}
 	if transfer.Key, err = am.identity.NormalizeSigningKey(ctx, transfer.Key, am.keyNormalization); err != nil {
-		return err
+		return nil, err
 	}
 	if transfer.From == "" {
 		transfer.From = transfer.Key
@@ -111,14 +114,11 @@ func (am *assetManager) validateTransfer(ctx context.Context, ns string, transfe
 	if transfer.To == "" {
 		transfer.To = transfer.Key
 	}
-	return nil
+	return pool, nil
 }
 
 func (am *assetManager) MintTokens(ctx context.Context, ns string, transfer *fftypes.TokenTransferInput, waitConfirm bool) (out *fftypes.TokenTransfer, err error) {
 	transfer.Type = fftypes.TokenTransferTypeMint
-	if err := am.validateTransfer(ctx, ns, transfer); err != nil {
-		return nil, err
-	}
 
 	sender := am.NewTransfer(ns, transfer)
 	if am.metrics.IsMetricsEnabled() {
@@ -134,9 +134,6 @@ func (am *assetManager) MintTokens(ctx context.Context, ns string, transfer *fft
 
 func (am *assetManager) BurnTokens(ctx context.Context, ns string, transfer *fftypes.TokenTransferInput, waitConfirm bool) (out *fftypes.TokenTransfer, err error) {
 	transfer.Type = fftypes.TokenTransferTypeBurn
-	if err := am.validateTransfer(ctx, ns, transfer); err != nil {
-		return nil, err
-	}
 
 	sender := am.NewTransfer(ns, transfer)
 	if am.metrics.IsMetricsEnabled() {
@@ -152,12 +149,6 @@ func (am *assetManager) BurnTokens(ctx context.Context, ns string, transfer *fft
 
 func (am *assetManager) TransferTokens(ctx context.Context, ns string, transfer *fftypes.TokenTransferInput, waitConfirm bool) (out *fftypes.TokenTransfer, err error) {
 	transfer.Type = fftypes.TokenTransferTypeTransfer
-	if err := am.validateTransfer(ctx, ns, transfer); err != nil {
-		return nil, err
-	}
-	if transfer.From == transfer.To {
-		return nil, i18n.NewError(ctx, coremsgs.MsgCannotTransferToSelf)
-	}
 
 	sender := am.NewTransfer(ns, transfer)
 	if am.metrics.IsMetricsEnabled() {
@@ -207,7 +198,7 @@ func (s *transferSender) resolve(ctx context.Context) (err error) {
 	return nil
 }
 
-func (s *transferSender) sendInternal(ctx context.Context, method sendMethod) error {
+func (s *transferSender) sendInternal(ctx context.Context, method sendMethod) (err error) {
 	if method == methodSendAndWait {
 		out, err := s.mgr.syncasync.WaitForTokenTransfer(ctx, s.namespace, s.transfer.LocalID, s.Send)
 		if out != nil {
@@ -216,34 +207,32 @@ func (s *transferSender) sendInternal(ctx context.Context, method sendMethod) er
 		return err
 	}
 
-	plugin, err := s.mgr.selectTokenPlugin(ctx, s.transfer.Connector)
-	if err != nil {
-		return err
-	}
-
-	if method == methodPrepare {
-		return nil
-	}
-
 	var op *fftypes.Operation
 	var pool *fftypes.TokenPool
 	err = s.mgr.database.RunAsGroup(ctx, func(ctx context.Context) (err error) {
-		pool, err = s.mgr.GetTokenPoolByNameOrID(ctx, s.namespace, s.transfer.Pool)
+		pool, err = s.mgr.validateTransfer(ctx, s.namespace, s.transfer)
 		if err != nil {
 			return err
 		}
-		if pool.State != fftypes.TokenPoolStateConfirmed {
-			return i18n.NewError(ctx, coremsgs.MsgTokenPoolNotConfirmed)
+		if s.transfer.Type == fftypes.TokenTransferTypeTransfer && s.transfer.From == s.transfer.To {
+			return i18n.NewError(ctx, coremsgs.MsgCannotTransferToSelf)
 		}
 
-		txid, err := s.mgr.txHelper.SubmitNewTransaction(ctx, s.namespace, fftypes.TransactionTypeTokenTransfer)
+		plugin, err := s.mgr.selectTokenPlugin(ctx, s.transfer.Connector)
 		if err != nil {
 			return err
 		}
 
+		if method == methodPrepare {
+			return nil
+		}
+
+		txid, err := s.mgr.txHelper.SubmitNewTransaction(ctx, s.namespace, fftypes.TransactionTypeTokenTransfer)
+		if err != nil {
+			return err
+		}
 		s.transfer.TX.ID = txid
 		s.transfer.TX.Type = fftypes.TransactionTypeTokenTransfer
-		s.transfer.TokenTransfer.Pool = pool.ID
 
 		op = fftypes.NewOperation(
 			plugin,
@@ -253,14 +242,12 @@ func (s *transferSender) sendInternal(ctx context.Context, method sendMethod) er
 		if err = txcommon.AddTokenTransferInputs(op, &s.transfer.TokenTransfer); err == nil {
 			err = s.mgr.database.InsertOperation(ctx, op)
 		}
-		if err != nil {
-			return err
-		}
-
 		return err
 	})
 	if err != nil {
 		return err
+	} else if method == methodPrepare {
+		return nil
 	}
 
 	// Write the transfer message outside of any DB transaction, as it will use the background message writer.
diff --git a/mocks/assetmocks/manager.go b/mocks/assetmocks/manager.go
index b18952de2..26cb35226 100644
--- a/mocks/assetmocks/manager.go
+++ b/mocks/assetmocks/manager.go
@@ -207,7 +207,7 @@ func (_m *Manager) GetTokenBalances(ctx context.Context, ns string, filter datab
 }
 
 // GetTokenConnectors provides a mock function with given fields: ctx, ns
-func (_m *Manager) GetTokenConnectors(ctx context.Context, ns string) ([]*fftypes.TokenConnector, error) {
+func (_m *Manager) GetTokenConnectors(ctx context.Context, ns string) []*fftypes.TokenConnector {
 	ret := _m.Called(ctx, ns)
 
 	var r0 []*fftypes.TokenConnector
@@ -219,14 +219,7 @@ func (_m *Manager) GetTokenConnectors(ctx context.Context, ns string) ([]*fftype
 		}
 	}
 
-	var r1 error
-	if rf, ok := ret.Get(1).(func(context.Context, string) error); ok {
-		r1 = rf(ctx, ns)
-	} else {
-		r1 = ret.Error(1)
-	}
-
-	return r0, r1
+	return r0
 }
 
 // GetTokenPool provides a mock function with given fields: ctx, ns, connector, poolName
diff --git a/pkg/fftypes/tokenapproval.go b/pkg/fftypes/tokenapproval.go
index 1e1c66dea..283b54202 100644
--- a/pkg/fftypes/tokenapproval.go
+++ b/pkg/fftypes/tokenapproval.go
@@ -25,7 +25,7 @@ type TokenApproval struct {
 	LocalID         *UUID          `ffstruct:"TokenApproval" json:"localId,omitempty" ffexcludeinput:"true"`
 	Pool            *UUID          `ffstruct:"TokenApproval" json:"pool,omitempty"`
 	TokenIndex      string         `ffstruct:"TokenApproval" json:"tokenIndex,omitempty"`
-	Connector       string         `ffstruct:"TokenApproval" json:"connector,omitempty"`
+	Connector       string         `ffstruct:"TokenApproval" json:"connector,omitempty" ffexcludeinput:"true"`
 	Key             string         `ffstruct:"TokenApproval" json:"key,omitempty"`
 	Operator        string         `ffstruct:"TokenApproval" json:"operator,omitempty"`
 	Approved        bool           `ffstruct:"TokenApproval" json:"approved"`
diff --git a/pkg/fftypes/tokentransfer.go b/pkg/fftypes/tokentransfer.go
index 1d034710c..821a34250 100644
--- a/pkg/fftypes/tokentransfer.go
+++ b/pkg/fftypes/tokentransfer.go
@@ -30,7 +30,7 @@ type TokenTransfer struct {
 	Pool            *UUID             `ffstruct:"TokenTransfer" json:"pool,omitempty"`
 	TokenIndex      string            `ffstruct:"TokenTransfer" json:"tokenIndex,omitempty"`
 	URI             string            `ffstruct:"TokenTransfer" json:"uri,omitempty" ffexcludeinput:"true"`
-	Connector       string            `ffstruct:"TokenTransfer" json:"connector,omitempty"`
+	Connector       string            `ffstruct:"TokenTransfer" json:"connector,omitempty" ffexcludeinput:"true"`
 	Namespace       string            `ffstruct:"TokenTransfer" json:"namespace,omitempty" ffexcludeinput:"true"`
 	Key             string            `ffstruct:"TokenTransfer" json:"key,omitempty"`
 	From            string            `ffstruct:"TokenTransfer" json:"from,omitempty" ffexcludeinput:"postTokenMint"`


Test patch:
diff --git a/internal/assets/manager_test.go b/internal/assets/manager_test.go
index bd1cfcc0a..2e1b1e3ce 100644
--- a/internal/assets/manager_test.go
+++ b/internal/assets/manager_test.go
@@ -125,14 +125,7 @@ func TestGetTokenConnectors(t *testing.T) {
 	am, cancel := newTestAssets(t)
 	defer cancel()
 
-	_, err := am.GetTokenConnectors(context.Background(), "ns1")
-	assert.NoError(t, err)
-}
-
-func TestGetTokenConnectorsBadNamespace(t *testing.T) {
-	am, cancel := newTestAssets(t)
-	defer cancel()
-
-	_, err := am.GetTokenConnectors(context.Background(), "")
-	assert.Regexp(t, "FF00140", err)
+	connectors := am.GetTokenConnectors(context.Background(), "ns1")
+	assert.Equal(t, 1, len(connectors))
+	assert.Equal(t, "magic-tokens", connectors[0].Name)
 }
diff --git a/internal/assets/token_approval_test.go b/internal/assets/token_approval_test.go
index c2973252e..a6132ca60 100644
--- a/internal/assets/token_approval_test.go
+++ b/internal/assets/token_approval_test.go
@@ -59,8 +59,9 @@ func TestTokenApprovalSuccess(t *testing.T) {
 		Pool: "pool1",
 	}
 	pool := &fftypes.TokenPool{
-		Locator: "F1",
-		State:   fftypes.TokenPoolStateConfirmed,
+		Locator:   "F1",
+		Connector: "magic-tokens",
+		State:     fftypes.TokenPoolStateConfirmed,
 	}
 
 	mdi := am.database.(*databasemocks.Plugin)
@@ -97,8 +98,9 @@ func TestTokenApprovalSuccessUnknownIdentity(t *testing.T) {
 		Pool: "pool1",
 	}
 	pool := &fftypes.TokenPool{
-		Locator: "F1",
-		State:   fftypes.TokenPoolStateConfirmed,
+		Locator:   "F1",
+		Connector: "magic-tokens",
+		State:     fftypes.TokenPoolStateConfirmed,
 	}
 
 	mdi := am.database.(*databasemocks.Plugin)
@@ -123,7 +125,7 @@ func TestTokenApprovalSuccessUnknownIdentity(t *testing.T) {
 	mom.AssertExpectations(t)
 }
 
-func TestApprovalUnknownConnectorNoConnectors(t *testing.T) {
+func TestApprovalBadNamespace(t *testing.T) {
 	am, cancel := newTestAssets(t)
 	defer cancel()
 
@@ -138,31 +140,11 @@ func TestApprovalUnknownConnectorNoConnectors(t *testing.T) {
 
 	am.tokens = make(map[string]tokens.Plugin)
 
-	_, err := am.TokenApproval(context.Background(), "ns1", approval, false)
-	assert.Regexp(t, "FF10292", err)
-}
-
-func TestApprovalUnknownConnectorMultipleConnectors(t *testing.T) {
-	am, cancel := newTestAssets(t)
-	defer cancel()
-
-	approval := &fftypes.TokenApprovalInput{
-		TokenApproval: fftypes.TokenApproval{
-			Approved: true,
-			Operator: "operator",
-			Key:      "key",
-		},
-		Pool: "pool1",
-	}
-
-	am.tokens["magic-tokens"] = nil
-	am.tokens["magic-tokens2"] = nil
-
-	_, err := am.TokenApproval(context.Background(), "ns1", approval, false)
-	assert.Regexp(t, "FF10292", err)
+	_, err := am.TokenApproval(context.Background(), "", approval, false)
+	assert.Regexp(t, "FF00140", err)
 }
 
-func TestApprovalUnknownConnectorBadNamespace(t *testing.T) {
+func TestApprovalBadConnector(t *testing.T) {
 	am, cancel := newTestAssets(t)
 	defer cancel()
 
@@ -174,35 +156,25 @@ func TestApprovalUnknownConnectorBadNamespace(t *testing.T) {
 		},
 		Pool: "pool1",
 	}
-
-	am.tokens = make(map[string]tokens.Plugin)
-
-	_, err := am.TokenApproval(context.Background(), "", approval, false)
-	assert.Regexp(t, "FF00140", err)
-}
-
-func TestApprovalBadConnector(t *testing.T) {
-	am, cancel := newTestAssets(t)
-	defer cancel()
-
-	approval := &fftypes.TokenApprovalInput{
-		TokenApproval: fftypes.TokenApproval{
-			Approved:  true,
-			Operator:  "operator",
-			Key:       "key",
-			Connector: "bad",
-		},
-		Pool: "pool1",
+	pool := &fftypes.TokenPool{
+		Locator:   "F1",
+		Connector: "bad",
+		State:     fftypes.TokenPoolStateConfirmed,
 	}
 
+	mdi := am.database.(*databasemocks.Plugin)
 	mim := am.identity.(*identitymanagermocks.Manager)
 	mim.On("NormalizeSigningKey", context.Background(), "key", identity.KeyNormalizationBlockchainPlugin).Return("0x12345", nil)
+	mdi.On("GetTokenPool", context.Background(), "ns1", "pool1").Return(pool, nil)
 
 	_, err := am.TokenApproval(context.Background(), "ns1", approval, false)
 	assert.Regexp(t, "FF10272", err)
+
+	mdi.AssertExpectations(t)
+	mim.AssertExpectations(t)
 }
 
-func TestApprovalUnknownPoolSuccess(t *testing.T) {
+func TestApprovalDefaultPoolSuccess(t *testing.T) {
 	am, cancel := newTestAssets(t)
 	defer cancel()
 
@@ -223,9 +195,10 @@ func TestApprovalUnknownPoolSuccess(t *testing.T) {
 	f.Limit(1).Count(true)
 	tokenPools := []*fftypes.TokenPool{
 		{
-			Name:    "pool1",
-			Locator: "F1",
-			State:   fftypes.TokenPoolStateConfirmed,
+			Name:      "pool1",
+			Locator:   "F1",
+			Connector: "magic-tokens",
+			State:     fftypes.TokenPoolStateConfirmed,
 		},
 	}
 	totalCount := int64(1)
@@ -237,7 +210,6 @@ func TestApprovalUnknownPoolSuccess(t *testing.T) {
 		info, _ := f.Finalize()
 		return info.Count && info.Limit == 1
 	}))).Return(tokenPools, filterResult, nil)
-	mdi.On("GetTokenPool", context.Background(), "ns1", "pool1").Return(tokenPools[0], nil)
 	mth.On("SubmitNewTransaction", context.Background(), "ns1", fftypes.TransactionTypeTokenApproval).Return(fftypes.NewUUID(), nil)
 	mdi.On("InsertOperation", context.Background(), mock.Anything).Return(nil)
 	mom.On("RunOperation", context.Background(), mock.MatchedBy(func(op *fftypes.PreparedOperation) bool {
@@ -254,7 +226,7 @@ func TestApprovalUnknownPoolSuccess(t *testing.T) {
 	mom.AssertExpectations(t)
 }
 
-func TestApprovalUnknownPoolNoPool(t *testing.T) {
+func TestApprovalDefaultPoolNoPool(t *testing.T) {
 	am, cancel := newTestAssets(t)
 	defer cancel()
 
@@ -318,19 +290,17 @@ func TestApprovalUnconfirmedPool(t *testing.T) {
 		Pool: "pool1",
 	}
 	pool := &fftypes.TokenPool{
-		Locator: "F1",
-		State:   fftypes.TokenPoolStatePending,
+		Locator:   "F1",
+		Connector: "magic-tokens",
+		State:     fftypes.TokenPoolStatePending,
 	}
 
 	mdi := am.database.(*databasemocks.Plugin)
-	mim := am.identity.(*identitymanagermocks.Manager)
-	mim.On("NormalizeSigningKey", context.Background(), "", identity.KeyNormalizationBlockchainPlugin).Return("0x12345", nil)
 	mdi.On("GetTokenPool", context.Background(), "ns1", "pool1").Return(pool, nil)
 
 	_, err := am.TokenApproval(context.Background(), "ns1", approval, false)
 	assert.Regexp(t, "FF10293", err)
 
-	mim.AssertExpectations(t)
 	mdi.AssertExpectations(t)
 }
 
@@ -345,12 +315,22 @@ func TestApprovalIdentityFail(t *testing.T) {
 		},
 		Pool: "pool1",
 	}
+	pool := &fftypes.TokenPool{
+		Locator:   "F1",
+		Connector: "magic-tokens",
+		State:     fftypes.TokenPoolStateConfirmed,
+	}
 
+	mdi := am.database.(*databasemocks.Plugin)
 	mim := am.identity.(*identitymanagermocks.Manager)
 	mim.On("NormalizeSigningKey", context.Background(), "", identity.KeyNormalizationBlockchainPlugin).Return("", fmt.Errorf("pop"))
+	mdi.On("GetTokenPool", context.Background(), "ns1", "pool1").Return(pool, nil)
 
 	_, err := am.TokenApproval(context.Background(), "ns1", approval, false)
 	assert.EqualError(t, err, "pop")
+
+	mdi.AssertExpectations(t)
+	mim.AssertExpectations(t)
 }
 
 func TestApprovalFail(t *testing.T) {
@@ -366,8 +346,9 @@ func TestApprovalFail(t *testing.T) {
 		Pool: "pool1",
 	}
 	pool := &fftypes.TokenPool{
-		Locator: "F1",
-		State:   fftypes.TokenPoolStateConfirmed,
+		Locator:   "F1",
+		Connector: "magic-tokens",
+		State:     fftypes.TokenPoolStateConfirmed,
 	}
 
 	mdi := am.database.(*databasemocks.Plugin)
@@ -404,8 +385,9 @@ func TestApprovalTransactionFail(t *testing.T) {
 		Pool: "pool1",
 	}
 	pool := &fftypes.TokenPool{
-		Locator: "F1",
-		State:   fftypes.TokenPoolStateConfirmed,
+		Locator:   "F1",
+		Connector: "magic-tokens",
+		State:     fftypes.TokenPoolStateConfirmed,
 	}
 
 	mdi := am.database.(*databasemocks.Plugin)
@@ -435,8 +417,9 @@ func TestApprovalOperationsFail(t *testing.T) {
 		Pool: "pool1",
 	}
 	pool := &fftypes.TokenPool{
-		Locator: "F1",
-		State:   fftypes.TokenPoolStateConfirmed,
+		Locator:   "F1",
+		Connector: "magic-tokens",
+		State:     fftypes.TokenPoolStateConfirmed,
 	}
 
 	mdi := am.database.(*databasemocks.Plugin)
@@ -465,8 +448,9 @@ func TestTokenApprovalConfirm(t *testing.T) {
 		Pool: "pool1",
 	}
 	pool := &fftypes.TokenPool{
-		Locator: "F1",
-		State:   fftypes.TokenPoolStateConfirmed,
+		Locator:   "F1",
+		Connector: "magic-tokens",
+		State:     fftypes.TokenPoolStateConfirmed,
 	}
 
 	mdi := am.database.(*databasemocks.Plugin)
@@ -507,15 +491,28 @@ func TestApprovalPrepare(t *testing.T) {
 
 	approval := &fftypes.TokenApprovalInput{
 		TokenApproval: fftypes.TokenApproval{
-			Approved:  true,
-			Operator:  "operator",
-			Key:       "key",
-			Connector: "magic-tokens",
+			Approved: true,
+			Operator: "operator",
+			Key:      "key",
 		},
 		Pool: "pool1",
 	}
+	pool := &fftypes.TokenPool{
+		Locator:   "F1",
+		Connector: "magic-tokens",
+		State:     fftypes.TokenPoolStateConfirmed,
+	}
 
 	sender := am.NewApproval("ns1", approval)
+
+	mdi := am.database.(*databasemocks.Plugin)
+	mim := am.identity.(*identitymanagermocks.Manager)
+	mim.On("NormalizeSigningKey", context.Background(), "key", identity.KeyNormalizationBlockchainPlugin).Return("0x12345", nil)
+	mdi.On("GetTokenPool", context.Background(), "ns1", "pool1").Return(pool, nil)
+
 	err := sender.Prepare(context.Background())
 	assert.NoError(t, err)
+
+	mdi.AssertExpectations(t)
+	mim.AssertExpectations(t)
 }
diff --git a/internal/assets/token_pool_test.go b/internal/assets/token_pool_test.go
index 2f05e1a08..62b8dc630 100644
--- a/internal/assets/token_pool_test.go
+++ b/internal/assets/token_pool_test.go
@@ -85,7 +85,7 @@ func TestCreateTokenPoolDuplicateName(t *testing.T) {
 	mdi.AssertExpectations(t)
 }
 
-func TestCreateTokenPoolUnknownConnectorSuccess(t *testing.T) {
+func TestCreateTokenPoolDefaultConnectorSuccess(t *testing.T) {
 	am, cancel := newTestAssets(t)
 	defer cancel()
 
@@ -118,7 +118,7 @@ func TestCreateTokenPoolUnknownConnectorSuccess(t *testing.T) {
 	mom.AssertExpectations(t)
 }
 
-func TestCreateTokenPoolUnknownConnectorNoConnectors(t *testing.T) {
+func TestCreateTokenPoolDefaultConnectorNoConnectors(t *testing.T) {
 	am, cancel := newTestAssets(t)
 	defer cancel()
 
@@ -140,7 +140,7 @@ func TestCreateTokenPoolUnknownConnectorNoConnectors(t *testing.T) {
 	mdm.AssertExpectations(t)
 }
 
-func TestCreateTokenPoolUnknownConnectorMultipleConnectors(t *testing.T) {
+func TestCreateTokenPoolDefaultConnectorMultipleConnectors(t *testing.T) {
 	am, cancel := newTestAssets(t)
 	defer cancel()
 
diff --git a/internal/assets/token_transfer_test.go b/internal/assets/token_transfer_test.go
index 6107fdbc5..99c30e4d8 100644
--- a/internal/assets/token_transfer_test.go
+++ b/internal/assets/token_transfer_test.go
@@ -32,7 +32,6 @@ import (
 	"github.com/hyperledger/firefly/mocks/txcommonmocks"
 	"github.com/hyperledger/firefly/pkg/database"
 	"github.com/hyperledger/firefly/pkg/fftypes"
-	"github.com/hyperledger/firefly/pkg/tokens"
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/mock"
 )
@@ -83,7 +82,8 @@ func TestMintTokensSuccess(t *testing.T) {
 		Pool: "pool1",
 	}
 	pool := &fftypes.TokenPool{
-		State: fftypes.TokenPoolStateConfirmed,
+		Connector: "magic-tokens",
+		State:     fftypes.TokenPoolStateConfirmed,
 	}
 
 	mdi := am.database.(*databasemocks.Plugin)
@@ -108,7 +108,7 @@ func TestMintTokensSuccess(t *testing.T) {
 	mom.AssertExpectations(t)
 }
 
-func TestMintTokenUnknownConnectorSuccess(t *testing.T) {
+func TestMintTokensBadConnector(t *testing.T) {
 	am, cancel := newTestAssets(t)
 	defer cancel()
 
@@ -119,67 +119,23 @@ func TestMintTokenUnknownConnectorSuccess(t *testing.T) {
 		Pool: "pool1",
 	}
 	pool := &fftypes.TokenPool{
-		State: fftypes.TokenPoolStateConfirmed,
+		Connector: "bad",
+		State:     fftypes.TokenPoolStateConfirmed,
 	}
 
 	mdi := am.database.(*databasemocks.Plugin)
 	mim := am.identity.(*identitymanagermocks.Manager)
-	mth := am.txHelper.(*txcommonmocks.Helper)
-	mom := am.operations.(*operationmocks.Manager)
 	mim.On("NormalizeSigningKey", context.Background(), "", identity.KeyNormalizationBlockchainPlugin).Return("0x12345", nil)
 	mdi.On("GetTokenPool", context.Background(), "ns1", "pool1").Return(pool, nil)
-	mth.On("SubmitNewTransaction", context.Background(), "ns1", fftypes.TransactionTypeTokenTransfer).Return(fftypes.NewUUID(), nil)
-	mdi.On("InsertOperation", context.Background(), mock.Anything).Return(nil)
-	mom.On("RunOperation", context.Background(), mock.MatchedBy(func(op *fftypes.PreparedOperation) bool {
-		data := op.Data.(transferData)
-		return op.Type == fftypes.OpTypeTokenTransfer && data.Pool == pool && data.Transfer == &mint.TokenTransfer
-	})).Return(nil, nil)
 
 	_, err := am.MintTokens(context.Background(), "ns1", mint, false)
-	assert.NoError(t, err)
+	assert.Regexp(t, "FF10272.*bad", err)
 
 	mdi.AssertExpectations(t)
 	mim.AssertExpectations(t)
-	mth.AssertExpectations(t)
-	mom.AssertExpectations(t)
-}
-
-func TestMintTokenUnknownConnectorNoConnectors(t *testing.T) {
-	am, cancel := newTestAssets(t)
-	defer cancel()
-
-	mint := &fftypes.TokenTransferInput{
-		TokenTransfer: fftypes.TokenTransfer{
-			Amount: *fftypes.NewFFBigInt(5),
-		},
-		Pool: "pool1",
-	}
-
-	am.tokens = make(map[string]tokens.Plugin)
-
-	_, err := am.MintTokens(context.Background(), "ns1", mint, false)
-	assert.Regexp(t, "FF10292", err)
-}
-
-func TestMintTokenUnknownConnectorMultipleConnectors(t *testing.T) {
-	am, cancel := newTestAssets(t)
-	defer cancel()
-
-	mint := &fftypes.TokenTransferInput{
-		TokenTransfer: fftypes.TokenTransfer{
-			Amount: *fftypes.NewFFBigInt(5),
-		},
-		Pool: "pool1",
-	}
-
-	am.tokens["magic-tokens"] = nil
-	am.tokens["magic-tokens2"] = nil
-
-	_, err := am.MintTokens(context.Background(), "ns1", mint, false)
-	assert.Regexp(t, "FF10292", err)
 }
 
-func TestMintTokenUnknownConnectorBadNamespace(t *testing.T) {
+func TestMintTokenBadNamespace(t *testing.T) {
 	am, cancel := newTestAssets(t)
 	defer cancel()
 
@@ -194,28 +150,7 @@ func TestMintTokenUnknownConnectorBadNamespace(t *testing.T) {
 	assert.Regexp(t, "FF00140", err)
 }
 
-func TestMintTokenBadConnector(t *testing.T) {
-	am, cancel := newTestAssets(t)
-	defer cancel()
-
-	mint := &fftypes.TokenTransferInput{
-		TokenTransfer: fftypes.TokenTransfer{
-			Connector: "bad",
-			Amount:    *fftypes.NewFFBigInt(5),
-		},
-		Pool: "pool1",
-	}
-
-	mim := am.identity.(*identitymanagermocks.Manager)
-	mim.On("NormalizeSigningKey", context.Background(), "", identity.KeyNormalizationBlockchainPlugin).Return("0x12345", nil)
-
-	_, err := am.MintTokens(context.Background(), "ns1", mint, false)
-	assert.Regexp(t, "FF10272", err)
-
-	mim.AssertExpectations(t)
-}
-
-func TestMintTokenUnknownPoolSuccess(t *testing.T) {
+func TestMintTokenDefaultPoolSuccess(t *testing.T) {
 	am, cancel := newTestAssets(t)
 	defer cancel()
 
@@ -234,8 +169,9 @@ func TestMintTokenUnknownPoolSuccess(t *testing.T) {
 	f.Limit(1).Count(true)
 	tokenPools := []*fftypes.TokenPool{
 		{
-			Name:  "pool1",
-			State: fftypes.TokenPoolStateConfirmed,
+			Name:      "pool1",
+			Connector: "magic-tokens",
+			State:     fftypes.TokenPoolStateConfirmed,
 		},
 	}
 	totalCount := int64(1)
@@ -247,7 +183,6 @@ func TestMintTokenUnknownPoolSuccess(t *testing.T) {
 		info, _ := f.Finalize()
 		return info.Count && info.Limit == 1
 	}))).Return(tokenPools, filterResult, nil)
-	mdi.On("GetTokenPool", context.Background(), "ns1", "pool1").Return(tokenPools[0], nil)
 	mth.On("SubmitNewTransaction", context.Background(), "ns1", fftypes.TransactionTypeTokenTransfer).Return(fftypes.NewUUID(), nil)
 	mdi.On("InsertOperation", context.Background(), mock.Anything).Return(nil)
 	mom.On("RunOperation", context.Background(), mock.MatchedBy(func(op *fftypes.PreparedOperation) bool {
@@ -264,7 +199,7 @@ func TestMintTokenUnknownPoolSuccess(t *testing.T) {
 	mom.AssertExpectations(t)
 }
 
-func TestMintTokenUnknownPoolNoPools(t *testing.T) {
+func TestMintTokenDefaultPoolNoPools(t *testing.T) {
 	am, cancel := newTestAssets(t)
 	defer cancel()
 
@@ -294,7 +229,7 @@ func TestMintTokenUnknownPoolNoPools(t *testing.T) {
 	mdi.AssertExpectations(t)
 }
 
-func TestMintTokenUnknownPoolMultiplePools(t *testing.T) {
+func TestMintTokenDefaultPoolMultiplePools(t *testing.T) {
 	am, cancel := newTestAssets(t)
 	defer cancel()
 
@@ -331,7 +266,7 @@ func TestMintTokenUnknownPoolMultiplePools(t *testing.T) {
 	mdi.AssertExpectations(t)
 }
 
-func TestMintTokenUnknownPoolBadNamespace(t *testing.T) {
+func TestMintTokenDefaultPoolBadNamespace(t *testing.T) {
 	am, cancel := newTestAssets(t)
 	defer cancel()
 
@@ -376,15 +311,12 @@ func TestMintTokensBadPool(t *testing.T) {
 	}
 
 	mdi := am.database.(*databasemocks.Plugin)
-	mim := am.identity.(*identitymanagermocks.Manager)
-	mim.On("NormalizeSigningKey", context.Background(), "", identity.KeyNormalizationBlockchainPlugin).Return("0x12345", nil)
 	mdi.On("GetTokenPool", context.Background(), "ns1", "pool1").Return(nil, fmt.Errorf("pop"))
 
 	_, err := am.MintTokens(context.Background(), "ns1", mint, false)
 	assert.EqualError(t, err, "pop")
 
 	mdi.AssertExpectations(t)
-	mim.AssertExpectations(t)
 }
 
 func TestMintTokensIdentityFail(t *testing.T) {
@@ -397,13 +329,20 @@ func TestMintTokensIdentityFail(t *testing.T) {
 		},
 		Pool: "pool1",
 	}
+	pool := &fftypes.TokenPool{
+		Connector: "magic-tokens",
+		State:     fftypes.TokenPoolStateConfirmed,
+	}
 
+	mdi := am.database.(*databasemocks.Plugin)
 	mim := am.identity.(*identitymanagermocks.Manager)
 	mim.On("NormalizeSigningKey", context.Background(), "", identity.KeyNormalizationBlockchainPlugin).Return("", fmt.Errorf("pop"))
+	mdi.On("GetTokenPool", context.Background(), "ns1", "pool1").Return(pool, nil)
 
 	_, err := am.MintTokens(context.Background(), "ns1", mint, false)
 	assert.EqualError(t, err, "pop")
 
+	mdi.AssertExpectations(t)
 	mim.AssertExpectations(t)
 }
 
@@ -418,7 +357,8 @@ func TestMintTokensFail(t *testing.T) {
 		Pool: "pool1",
 	}
 	pool := &fftypes.TokenPool{
-		State: fftypes.TokenPoolStateConfirmed,
+		Connector: "magic-tokens",
+		State:     fftypes.TokenPoolStateConfirmed,
 	}
 
 	mdi := am.database.(*databasemocks.Plugin)
@@ -454,8 +394,9 @@ func TestMintTokensOperationFail(t *testing.T) {
 		Pool: "pool1",
 	}
 	pool := &fftypes.TokenPool{
-		Locator: "F1",
-		State:   fftypes.TokenPoolStateConfirmed,
+		Locator:   "F1",
+		Connector: "magic-tokens",
+		State:     fftypes.TokenPoolStateConfirmed,
 	}
 
 	mdi := am.database.(*databasemocks.Plugin)
@@ -485,7 +426,8 @@ func TestMintTokensConfirm(t *testing.T) {
 		Pool: "pool1",
 	}
 	pool := &fftypes.TokenPool{
-		State: fftypes.TokenPoolStateConfirmed,
+		Connector: "magic-tokens",
+		State:     fftypes.TokenPoolStateConfirmed,
 	}
 
 	mdi := am.database.(*databasemocks.Plugin)
@@ -529,7 +471,8 @@ func TestBurnTokensSuccess(t *testing.T) {
 		Pool: "pool1",
 	}
 	pool := &fftypes.TokenPool{
-		State: fftypes.TokenPoolStateConfirmed,
+		Connector: "magic-tokens",
+		State:     fftypes.TokenPoolStateConfirmed,
 	}
 
 	mdi := am.database.(*databasemocks.Plugin)
@@ -564,13 +507,20 @@ func TestBurnTokensIdentityFail(t *testing.T) {
 		},
 		Pool: "pool1",
 	}
+	pool := &fftypes.TokenPool{
+		Connector: "magic-tokens",
+		State:     fftypes.TokenPoolStateConfirmed,
+	}
 
+	mdi := am.database.(*databasemocks.Plugin)
 	mim := am.identity.(*identitymanagermocks.Manager)
 	mim.On("NormalizeSigningKey", context.Background(), "", identity.KeyNormalizationBlockchainPlugin).Return("", fmt.Errorf("pop"))
+	mdi.On("GetTokenPool", context.Background(), "ns1", "pool1").Return(pool, nil)
 
 	_, err := am.BurnTokens(context.Background(), "ns1", burn, false)
 	assert.EqualError(t, err, "pop")
 
+	mdi.AssertExpectations(t)
 	mim.AssertExpectations(t)
 }
 
@@ -585,7 +535,8 @@ func TestBurnTokensConfirm(t *testing.T) {
 		Pool: "pool1",
 	}
 	pool := &fftypes.TokenPool{
-		State: fftypes.TokenPoolStateConfirmed,
+		Connector: "magic-tokens",
+		State:     fftypes.TokenPoolStateConfirmed,
 	}
 
 	mdi := am.database.(*databasemocks.Plugin)
@@ -632,7 +583,8 @@ func TestTransferTokensSuccess(t *testing.T) {
 		Pool: "pool1",
 	}
 	pool := &fftypes.TokenPool{
-		State: fftypes.TokenPoolStateConfirmed,
+		Connector: "magic-tokens",
+		State:     fftypes.TokenPoolStateConfirmed,
 	}
 
 	mdi := am.database.(*databasemocks.Plugin)
@@ -670,19 +622,17 @@ func TestTransferTokensUnconfirmedPool(t *testing.T) {
 		Pool: "pool1",
 	}
 	pool := &fftypes.TokenPool{
-		Locator: "F1",
-		State:   fftypes.TokenPoolStatePending,
+		Locator:   "F1",
+		Connector: "magic-tokens",
+		State:     fftypes.TokenPoolStatePending,
 	}
 
 	mdi := am.database.(*databasemocks.Plugin)
-	mim := am.identity.(*identitymanagermocks.Manager)
-	mim.On("NormalizeSigningKey", context.Background(), "", identity.KeyNormalizationBlockchainPlugin).Return("0x12345", nil)
 	mdi.On("GetTokenPool", context.Background(), "ns1", "pool1").Return(pool, nil)
 
 	_, err := am.TransferTokens(context.Background(), "ns1", transfer, false)
 	assert.Regexp(t, "FF10293", err)
 
-	mim.AssertExpectations(t)
 	mdi.AssertExpectations(t)
 }
 
@@ -698,13 +648,20 @@ func TestTransferTokensIdentityFail(t *testing.T) {
 		},
 		Pool: "pool1",
 	}
+	pool := &fftypes.TokenPool{
+		Connector: "magic-tokens",
+		State:     fftypes.TokenPoolStateConfirmed,
+	}
 
+	mdi := am.database.(*databasemocks.Plugin)
 	mim := am.identity.(*identitymanagermocks.Manager)
 	mim.On("NormalizeSigningKey", context.Background(), "", identity.KeyNormalizationBlockchainPlugin).Return("", fmt.Errorf("pop"))
+	mdi.On("GetTokenPool", context.Background(), "ns1", "pool1").Return(pool, nil)
 
 	_, err := am.TransferTokens(context.Background(), "ns1", transfer, false)
 	assert.EqualError(t, err, "pop")
 
+	mdi.AssertExpectations(t)
 	mim.AssertExpectations(t)
 }
 
@@ -715,13 +672,20 @@ func TestTransferTokensNoFromOrTo(t *testing.T) {
 	transfer := &fftypes.TokenTransferInput{
 		Pool: "pool1",
 	}
+	pool := &fftypes.TokenPool{
+		Connector: "magic-tokens",
+		State:     fftypes.TokenPoolStateConfirmed,
+	}
 
+	mdi := am.database.(*databasemocks.Plugin)
 	mim := am.identity.(*identitymanagermocks.Manager)
 	mim.On("NormalizeSigningKey", context.Background(), "", identity.KeyNormalizationBlockchainPlugin).Return("0x12345", nil)
+	mdi.On("GetTokenPool", context.Background(), "ns1", "pool1").Return(pool, nil)
 
 	_, err := am.TransferTokens(context.Background(), "ns1", transfer, false)
 	assert.Regexp(t, "FF10280", err)
 
+	mdi.AssertExpectations(t)
 	mim.AssertExpectations(t)
 }
 
@@ -738,8 +702,9 @@ func TestTransferTokensTransactionFail(t *testing.T) {
 		Pool: "pool1",
 	}
 	pool := &fftypes.TokenPool{
-		Locator: "F1",
-		State:   fftypes.TokenPoolStateConfirmed,
+		Locator:   "F1",
+		Connector: "magic-tokens",
+		State:     fftypes.TokenPoolStateConfirmed,
 	}
 
 	mdi := am.database.(*databasemocks.Plugin)
@@ -785,7 +750,8 @@ func TestTransferTokensWithBroadcastMessage(t *testing.T) {
 		},
 	}
 	pool := &fftypes.TokenPool{
-		State: fftypes.TokenPoolStateConfirmed,
+		Connector: "magic-tokens",
+		State:     fftypes.TokenPoolStateConfirmed,
 	}
 
 	mdi := am.database.(*databasemocks.Plugin)
@@ -847,7 +813,8 @@ func TestTransferTokensWithBroadcastMessageSendFail(t *testing.T) {
 		},
 	}
 	pool := &fftypes.TokenPool{
-		State: fftypes.TokenPoolStateConfirmed,
+		Connector: "magic-tokens",
+		State:     fftypes.TokenPoolStateConfirmed,
 	}
 
 	mdi := am.database.(*databasemocks.Plugin)
@@ -897,10 +864,8 @@ func TestTransferTokensWithBroadcastPrepareFail(t *testing.T) {
 		},
 	}
 
-	mim := am.identity.(*identitymanagermocks.Manager)
 	mbm := am.broadcast.(*broadcastmocks.Manager)
 	mms := &sysmessagingmocks.MessageSender{}
-	mim.On("NormalizeSigningKey", context.Background(), "", identity.KeyNormalizationBlockchainPlugin).Return("0x12345", nil)
 	mbm.On("NewBroadcast", "ns1", transfer.Message).Return(mms)
 	mms.On("Prepare", context.Background()).Return(fmt.Errorf("pop"))
 
@@ -908,7 +873,6 @@ func TestTransferTokensWithBroadcastPrepareFail(t *testing.T) {
 	assert.EqualError(t, err, "pop")
 
 	mbm.AssertExpectations(t)
-	mim.AssertExpectations(t)
 	mms.AssertExpectations(t)
 }
 
@@ -941,7 +905,8 @@ func TestTransferTokensWithPrivateMessage(t *testing.T) {
 		},
 	}
 	pool := &fftypes.TokenPool{
-		State: fftypes.TokenPoolStateConfirmed,
+		Connector: "magic-tokens",
+		State:     fftypes.TokenPoolStateConfirmed,
 	}
 
 	mdi := am.database.(*databasemocks.Plugin)
@@ -1000,13 +965,8 @@ func TestTransferTokensWithInvalidMessage(t *testing.T) {
 		},
 	}
 
-	mim := am.identity.(*identitymanagermocks.Manager)
-	mim.On("NormalizeSigningKey", context.Background(), "", identity.KeyNormalizationBlockchainPlugin).Return("0x12345", nil)
-
 	_, err := am.TransferTokens(context.Background(), "ns1", transfer, false)
 	assert.Regexp(t, "FF10287", err)
-
-	mim.AssertExpectations(t)
 }
 
 func TestTransferTokensConfirm(t *testing.T) {
@@ -1022,7 +982,8 @@ func TestTransferTokensConfirm(t *testing.T) {
 		Pool: "pool1",
 	}
 	pool := &fftypes.TokenPool{
-		State: fftypes.TokenPoolStateConfirmed,
+		Connector: "magic-tokens",
+		State:     fftypes.TokenPoolStateConfirmed,
 	}
 
 	mdi := am.database.(*databasemocks.Plugin)
@@ -1085,7 +1046,8 @@ func TestTransferTokensWithBroadcastConfirm(t *testing.T) {
 		},
 	}
 	pool := &fftypes.TokenPool{
-		State: fftypes.TokenPoolStateConfirmed,
+		Connector: "magic-tokens",
+		State:     fftypes.TokenPoolStateConfirmed,
 	}
 
 	mdi := am.database.(*databasemocks.Plugin)
@@ -1146,14 +1108,11 @@ func TestTransferTokensPoolNotFound(t *testing.T) {
 	}
 
 	mdi := am.database.(*databasemocks.Plugin)
-	mim := am.identity.(*identitymanagermocks.Manager)
-	mim.On("NormalizeSigningKey", context.Background(), "", identity.KeyNormalizationBlockchainPlugin).Return("0x12345", nil)
 	mdi.On("GetTokenPool", context.Background(), "ns1", "pool1").Return(nil, nil)
 
 	_, err := am.TransferTokens(context.Background(), "ns1", transfer, false)
 	assert.Regexp(t, "FF10109", err)
 
-	mim.AssertExpectations(t)
 	mdi.AssertExpectations(t)
 }
 
@@ -1163,16 +1122,28 @@ func TestTransferPrepare(t *testing.T) {
 
 	transfer := &fftypes.TokenTransferInput{
 		TokenTransfer: fftypes.TokenTransfer{
-			Type:      fftypes.TokenTransferTypeTransfer,
-			From:      "A",
-			To:        "B",
-			Connector: "magic-tokens",
-			Amount:    *fftypes.NewFFBigInt(5),
+			Type:   fftypes.TokenTransferTypeTransfer,
+			From:   "A",
+			To:     "B",
+			Amount: *fftypes.NewFFBigInt(5),
 		},
+		Pool: "pool1",
+	}
+	pool := &fftypes.TokenPool{
+		Connector: "magic-tokens",
+		State:     fftypes.TokenPoolStateConfirmed,
 	}
 
 	sender := am.NewTransfer("ns1", transfer)
 
+	mdi := am.database.(*databasemocks.Plugin)
+	mim := am.identity.(*identitymanagermocks.Manager)
+	mim.On("NormalizeSigningKey", context.Background(), "", identity.KeyNormalizationBlockchainPlugin).Return("0x12345", nil)
+	mdi.On("GetTokenPool", context.Background(), "ns1", "pool1").Return(pool, nil)
+
 	err := sender.Prepare(context.Background())
 	assert.NoError(t, err)
+
+	mdi.AssertExpectations(t)
+	mim.AssertExpectations(t)
 }