Repository: desmos-labs/desmos
Pull request #784 (2022-03-21 12:05:42)

fix: fixed how profiles-related data are deleted
## Description
This PR fixes how DTag transfer requests, app links and chain links are deleted. Particularly, there was a bug inside the `DeleteAllUserAppLinks` that did not remove all the keys (the `ApplicationLinkClientIDKey` was left there). 

I have replaced the individual key removal from within that method with a call to the properly implemented `DeleteApplicationLink` instead. 

I have also improved `DeleteApplicationLink` and `DeleteChainLink` methods to require an `ApplicationLink` and a `ChainLink` respectively. Now they do not return any error if the link is not found, and that responsibility (existence check) is moved to the called.

<!-- Add a description of the changes that this PR introduces and the files that
are the most critical to review. -->

Depends-On: #787

---

### Author Checklist

*All items are required. Please add a note to the item if the item is not applicable and
please add links to any relevant follow up issues.*

I have...

- [x] included the correct [type prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title
- [ ] added `!` to the type prefix if API or client breaking change
- [ ] targeted the correct branch (see [PR Targeting](https://github.com/desmos-labs/desmos/blob/master/CONTRIBUTING.md#pr-targeting))
- [ ] provided a link to the relevant issue or specification
- [ ] followed the guidelines for [building modules](https://docs.cosmos.network/v0.44/building-modules/intro.html)
- [ ] included the necessary unit and integration [tests](https://github.com/desmos-labs/desmos/blob/master/CONTRIBUTING.md#testing)
- [x] added a changelog entry to `CHANGELOG.md`
- [ ] included comments for [documenting Go code](https://blog.golang.org/godoc)
- [ ] updated the relevant documentation or specification
- [ ] reviewed "Files changed" and left comments if necessary
- [ ] confirmed all CI checks have passed

### Reviewers Checklist

*All items are required. Please add a note if the item is not applicable and please add
your handle next to the items reviewed if you only reviewed selected items.*

I have...

- [ ] confirmed the correct [type prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title
- [ ] confirmed `!` in the type prefix if API or client breaking change
- [ ] confirmed all author checklist items have been addressed
- [ ] reviewed state machine logic
- [ ] reviewed API design and naming
- [ ] reviewed documentation is accurate
- [ ] reviewed tests and test coverage
- [ ] manually tested (if applicable)

codecov[bot]: # [Codecov](https://codecov.io/gh/desmos-labs/desmos/pull/784?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=desmos-labs) Report
> Merging [#784](https://codecov.io/gh/desmos-labs/desmos/pull/784?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=desmos-labs) (45ed167) into [master](https://codecov.io/gh/desmos-labs/desmos/commit/8140a5c2460dca25a6908d6f10ad85c5becda054?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=desmos-labs) (8140a5c) will **decrease** coverage by `0.26%`.
> The diff coverage is `74.19%`.

```diff
@@            Coverage Diff             @@
##           master     #784      +/-   ##
==========================================
- Coverage   81.30%   81.04%   -0.27%     
==========================================
  Files          76       76              
  Lines        6495     6472      -23     
==========================================
- Hits         5281     5245      -36     
- Misses        970      985      +15     
+ Partials      244      242       -2     
```


| [Impacted Files](https://codecov.io/gh/desmos-labs/desmos/pull/784?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=desmos-labs) | Coverage Δ | |
|---|---|---|
| [x/profiles/keeper/msg\_server\_app\_link.go](https://codecov.io/gh/desmos-labs/desmos/pull/784/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=desmos-labs#diff-eC9wcm9maWxlcy9rZWVwZXIvbXNnX3NlcnZlcl9hcHBfbGluay5nbw==) | `0.00% <0.00%> (ø)` | |
| [x/profiles/keeper/keeper\_app\_links.go](https://codecov.io/gh/desmos-labs/desmos/pull/784/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=desmos-labs#diff-eC9wcm9maWxlcy9rZWVwZXIva2VlcGVyX2FwcF9saW5rcy5nbw==) | `81.15% <85.71%> (+4.90%)` | :arrow_up: |
| [x/profiles/keeper/keeper\_chain\_links.go](https://codecov.io/gh/desmos-labs/desmos/pull/784/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=desmos-labs#diff-eC9wcm9maWxlcy9rZWVwZXIva2VlcGVyX2NoYWluX2xpbmtzLmdv) | `82.69% <100.00%> (-2.06%)` | :arrow_down: |
| [x/profiles/keeper/msg\_server\_chain\_link.go](https://codecov.io/gh/desmos-labs/desmos/pull/784/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=desmos-labs#diff-eC9wcm9maWxlcy9rZWVwZXIvbXNnX3NlcnZlcl9jaGFpbl9saW5rLmdv) | `100.00% <100.00%> (ø)` | |
| [x/profiles/legacy/v1beta1/store.go](https://codecov.io/gh/desmos-labs/desmos/pull/784/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=desmos-labs#diff-eC9wcm9maWxlcy9sZWdhY3kvdjFiZXRhMS9zdG9yZS5nbw==) | `83.53% <100.00%> (-1.38%)` | :arrow_down: |
| [x/profiles/legacy/v1beta1/keeper.go](https://codecov.io/gh/desmos-labs/desmos/pull/784/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=desmos-labs#diff-eC9wcm9maWxlcy9sZWdhY3kvdjFiZXRhMS9rZWVwZXIuZ28=) | `74.48% <0.00%> (-8.97%)` | :arrow_down: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/desmos-labs/desmos/pull/784?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=desmos-labs).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=desmos-labs)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/desmos-labs/desmos/pull/784?src=pr&el=footer&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=desmos-labs). Last update [8140a5c...45ed167](https://codecov.io/gh/desmos-labs/desmos/pull/784?src=pr&el=lastupdated&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=desmos-labs). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=desmos-labs).


Patch:
diff --git a/.changeset/entries/7f7c55e22eee3075ed73848811f459c72643ab119e8928a1f464b3cb8bec009d.yaml b/.changeset/entries/7f7c55e22eee3075ed73848811f459c72643ab119e8928a1f464b3cb8bec009d.yaml
new file mode 100644
index 00000000..c6f83f8b
--- /dev/null
+++ b/.changeset/entries/7f7c55e22eee3075ed73848811f459c72643ab119e8928a1f464b3cb8bec009d.yaml
@@ -0,0 +1,6 @@
+type: fix
+module: x/profiles
+pull_request: 784
+description: Fixed how the profiles data are deleted (DTag transfer requests, chain link and application links)
+backward_compatible: true
+date: 2022-03-21T12:10:14.687869312Z
diff --git a/x/profiles/keeper/keeper_app_links.go b/x/profiles/keeper/keeper_app_links.go
index c490df33..3c808618 100644
--- a/x/profiles/keeper/keeper_app_links.go
+++ b/x/profiles/keeper/keeper_app_links.go
@@ -40,6 +40,12 @@ func (k Keeper) SaveApplicationLink(ctx sdk.Context, link types.ApplicationLink)
 	return nil
 }
 
+// HasApplicationLink tells whether the given application link exists
+func (k Keeper) HasApplicationLink(ctx sdk.Context, user, application, username string) bool {
+	store := ctx.KVStore(k.storeKey)
+	return store.Has(types.UserApplicationLinkKey(user, application, username))
+}
+
 // GetApplicationLink returns the link for the given application and username.
 // If the link is not found returns an error instead.
 func (k Keeper) GetApplicationLink(ctx sdk.Context, user, application, username string) (types.ApplicationLink, bool, error) {
@@ -86,27 +92,10 @@ func (k Keeper) GetApplicationLinkByClientID(ctx sdk.Context, clientID string) (
 
 // DeleteApplicationLink removes the application link associated to the given user,
 // for the given application and username
-func (k Keeper) DeleteApplicationLink(ctx sdk.Context, user string, application, username string) error {
-	// Get the link to obtain the client id
-	link, found, err := k.GetApplicationLink(ctx, user, application, username)
-	if err != nil {
-		return err
-	}
-
-	if !found {
-		return sdkerrors.Wrap(sdkerrors.ErrNotFound, "application link not found")
-	}
-
-	if link.User != user {
-		return sdkerrors.Wrap(sdkerrors.ErrorInvalidSigner, "cannot delete the application link of another user")
-	}
-
-	// Delete the data
+func (k Keeper) DeleteApplicationLink(ctx sdk.Context, appLink types.ApplicationLink) {
 	store := ctx.KVStore(k.storeKey)
-	store.Delete(types.UserApplicationLinkKey(user, application, username))
-	store.Delete(types.ApplicationLinkClientIDKey(link.OracleRequest.ClientID))
-
-	return nil
+	store.Delete(types.UserApplicationLinkKey(appLink.User, appLink.Data.Application, appLink.Data.Username))
+	store.Delete(types.ApplicationLinkClientIDKey(appLink.OracleRequest.ClientID))
 }
 
 // DeleteAllUserApplicationLinks delete all the applications links associated with the given user
@@ -117,8 +106,7 @@ func (k Keeper) DeleteAllUserApplicationLinks(ctx sdk.Context, user string) {
 		return false
 	})
 
-	store := ctx.KVStore(k.storeKey)
 	for _, link := range links {
-		store.Delete(types.UserApplicationLinkKey(link.User, link.Data.Application, link.Data.Username))
+		k.DeleteApplicationLink(ctx, link)
 	}
 }
diff --git a/x/profiles/keeper/keeper_chain_links.go b/x/profiles/keeper/keeper_chain_links.go
index 898cda3f..5040abe3 100644
--- a/x/profiles/keeper/keeper_chain_links.go
+++ b/x/profiles/keeper/keeper_chain_links.go
@@ -49,6 +49,12 @@ func (k Keeper) SaveChainLink(ctx sdk.Context, link types.ChainLink) error {
 	return nil
 }
 
+// HasChainLink tells whether the given chain link exists or not
+func (k Keeper) HasChainLink(ctx sdk.Context, owner, chainName, target string) bool {
+	store := ctx.KVStore(k.storeKey)
+	return store.Has(types.ChainLinksStoreKey(owner, chainName, target))
+}
+
 // GetChainLink returns the chain link for the given owner, chain name and target.
 // If such link does not exist, returns false instead.
 func (k Keeper) GetChainLink(ctx sdk.Context, owner, chainName, target string) (types.ChainLink, bool) {
@@ -63,17 +69,9 @@ func (k Keeper) GetChainLink(ctx sdk.Context, owner, chainName, target string) (
 }
 
 // DeleteChainLink deletes the link associated with the given address and chain name
-func (k Keeper) DeleteChainLink(ctx sdk.Context, owner, chainName, target string) error {
+func (k Keeper) DeleteChainLink(ctx sdk.Context, link types.ChainLink) {
 	store := ctx.KVStore(k.storeKey)
-	key := types.ChainLinksStoreKey(owner, chainName, target)
-	if !store.Has(key) {
-		return sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest,
-			"chain link between %s and %s for chain name %s not found",
-			owner, target, chainName,
-		)
-	}
-	store.Delete(types.ChainLinksStoreKey(owner, chainName, target))
-	return nil
+	store.Delete(types.ChainLinksStoreKey(link.User, link.ChainConfig.Name, link.GetAddressData().GetValue()))
 }
 
 // DeleteAllUserChainLinks deletes all the chain links associated with the given user
@@ -84,9 +82,7 @@ func (k Keeper) DeleteAllUserChainLinks(ctx sdk.Context, user string) {
 		return false
 	})
 
-	store := ctx.KVStore(k.storeKey)
 	for _, link := range links {
-		address := link.Address.GetCachedValue().(types.AddressData)
-		store.Delete(types.ChainLinksStoreKey(link.User, link.ChainConfig.Name, address.GetValue()))
+		k.DeleteChainLink(ctx, link)
 	}
 }
diff --git a/x/profiles/keeper/keeper_dtag_transfers.go b/x/profiles/keeper/keeper_dtag_transfers.go
index 0a1b79b9..fec5e863 100644
--- a/x/profiles/keeper/keeper_dtag_transfers.go
+++ b/x/profiles/keeper/keeper_dtag_transfers.go
@@ -29,6 +29,12 @@ func (k Keeper) SaveDTagTransferRequest(ctx sdk.Context, request types.DTagTrans
 	return nil
 }
 
+// HasDTagTransferRequest tells whether a DTag transfer request between the sender and recipient exists or not
+func (k Keeper) HasDTagTransferRequest(ctx sdk.Context, sender, recipient string) bool {
+	store := ctx.KVStore(k.storeKey)
+	return store.Has(types.DTagTransferRequestStoreKey(sender, recipient))
+}
+
 // GetDTagTransferRequest retries the DTag transfer request made from the specified sender to the given receiver.
 // If the request was not found, returns false instead.
 func (k Keeper) GetDTagTransferRequest(ctx sdk.Context, sender, receiver string) (types.DTagTransferRequest, bool, error) {
@@ -62,15 +68,9 @@ func (k Keeper) GetDTagTransferRequests(ctx sdk.Context) (requests []types.DTagT
 }
 
 // DeleteDTagTransferRequest deletes the transfer request made from the sender towards the recipient
-func (k Keeper) DeleteDTagTransferRequest(ctx sdk.Context, sender, recipient string) error {
+func (k Keeper) DeleteDTagTransferRequest(ctx sdk.Context, sender, recipient string) {
 	store := ctx.KVStore(k.storeKey)
-	key := types.DTagTransferRequestStoreKey(sender, recipient)
-	if !store.Has(key) {
-		return sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "request from %s to %s not found", sender, recipient)
-	}
-
-	store.Delete(key)
-	return nil
+	store.Delete(types.DTagTransferRequestStoreKey(sender, recipient))
 }
 
 // DeleteAllUserIncomingDTagTransferRequests deletes all the requests made to the given user
@@ -81,8 +81,7 @@ func (k Keeper) DeleteAllUserIncomingDTagTransferRequests(ctx sdk.Context, recei
 		return false
 	})
 
-	store := ctx.KVStore(k.storeKey)
 	for _, request := range requests {
-		store.Delete(types.DTagTransferRequestStoreKey(request.Sender, request.Receiver))
+		k.DeleteDTagTransferRequest(ctx, request.Sender, request.Receiver)
 	}
 }
diff --git a/x/profiles/keeper/msg_server_app_link.go b/x/profiles/keeper/msg_server_app_link.go
index d3097e1c..d842b421 100644
--- a/x/profiles/keeper/msg_server_app_link.go
+++ b/x/profiles/keeper/msg_server_app_link.go
@@ -69,11 +69,19 @@ func (k msgServer) UnlinkApplication(
 ) (*types.MsgUnlinkApplicationResponse, error) {
 	ctx := sdk.UnwrapSDKContext(goCtx)
 
-	err := k.DeleteApplicationLink(ctx, msg.Signer, msg.Application, msg.Username)
+	// Get the link
+	link, found, err := k.GetApplicationLink(ctx, msg.Signer, msg.Application, msg.Username)
 	if err != nil {
 		return nil, err
 	}
 
+	if !found {
+		return nil, sdkerrors.Wrap(sdkerrors.ErrNotFound, "application link not found")
+	}
+
+	// Delete the link
+	k.DeleteApplicationLink(ctx, link)
+
 	k.Logger(ctx).Info("Application link removed",
 		"application", msg.Application,
 		"username", msg.Username,
diff --git a/x/profiles/keeper/msg_server_chain_link.go b/x/profiles/keeper/msg_server_chain_link.go
index 0035c5c1..1b976a2f 100644
--- a/x/profiles/keeper/msg_server_chain_link.go
+++ b/x/profiles/keeper/msg_server_chain_link.go
@@ -4,6 +4,8 @@ import (
 	"context"
 	"time"
 
+	sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
+
 	sdk "github.com/cosmos/cosmos-sdk/types"
 
 	"github.com/desmos-labs/desmos/v3/x/profiles/types"
@@ -37,10 +39,15 @@ func (k msgServer) LinkChainAccount(goCtx context.Context, msg *types.MsgLinkCha
 func (k msgServer) UnlinkChainAccount(goCtx context.Context, msg *types.MsgUnlinkChainAccount) (*types.MsgUnlinkChainAccountResponse, error) {
 	ctx := sdk.UnwrapSDKContext(goCtx)
 
-	if err := k.DeleteChainLink(ctx, msg.Owner, msg.ChainName, msg.Target); err != nil {
-		return &types.MsgUnlinkChainAccountResponse{}, err
+	// Get the chain link
+	link, found := k.GetChainLink(ctx, msg.Owner, msg.ChainName, msg.Target)
+	if !found {
+		return nil, sdkerrors.Wrap(sdkerrors.ErrNotFound, "chain link not found")
 	}
 
+	// Delete the link
+	k.DeleteChainLink(ctx, link)
+
 	ctx.EventManager().EmitEvent(sdk.NewEvent(
 		types.EventTypeUnlinkChainAccount,
 		sdk.NewAttribute(types.AttributeKeyChainLinkSourceAddress, msg.Target),
diff --git a/x/profiles/keeper/msg_server_dtag_transfers.go b/x/profiles/keeper/msg_server_dtag_transfers.go
index c811a395..29466956 100644
--- a/x/profiles/keeper/msg_server_dtag_transfers.go
+++ b/x/profiles/keeper/msg_server_dtag_transfers.go
@@ -62,11 +62,14 @@ func (k msgServer) RequestDTagTransfer(goCtx context.Context, msg *types.MsgRequ
 func (k msgServer) CancelDTagTransferRequest(goCtx context.Context, msg *types.MsgCancelDTagTransferRequest) (*types.MsgCancelDTagTransferRequestResponse, error) {
 	ctx := sdk.UnwrapSDKContext(goCtx)
 
-	err := k.DeleteDTagTransferRequest(ctx, msg.Sender, msg.Receiver)
-	if err != nil {
-		return nil, err
+	// Check if the request exists
+	if !k.HasDTagTransferRequest(ctx, msg.Sender, msg.Receiver) {
+		return nil, sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "request from %s to %s not found", msg.Sender, msg.Receiver)
 	}
 
+	// Delete the request
+	k.DeleteDTagTransferRequest(ctx, msg.Sender, msg.Receiver)
+
 	ctx.EventManager().EmitEvents(sdk.Events{
 		sdk.NewEvent(
 			sdk.EventTypeMessage,
@@ -192,11 +195,14 @@ func (k msgServer) AcceptDTagTransferRequest(goCtx context.Context, msg *types.M
 func (k msgServer) RefuseDTagTransferRequest(goCtx context.Context, msg *types.MsgRefuseDTagTransferRequest) (*types.MsgRefuseDTagTransferRequestResponse, error) {
 	ctx := sdk.UnwrapSDKContext(goCtx)
 
-	err := k.DeleteDTagTransferRequest(ctx, msg.Sender, msg.Receiver)
-	if err != nil {
-		return nil, err
+	// Check if the request exists
+	if !k.HasDTagTransferRequest(ctx, msg.Sender, msg.Receiver) {
+		return nil, sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "request from %s to %s not found", msg.Sender, msg.Receiver)
 	}
 
+	// Delete the request
+	k.DeleteDTagTransferRequest(ctx, msg.Sender, msg.Receiver)
+
 	ctx.EventManager().EmitEvents(sdk.Events{
 		sdk.NewEvent(
 			sdk.EventTypeMessage,
diff --git a/x/profiles/legacy/v4/keeper.go b/x/profiles/legacy/v4/keeper.go
index 71b6b2c0..3e9ec69e 100644
--- a/x/profiles/legacy/v4/keeper.go
+++ b/x/profiles/legacy/v4/keeper.go
@@ -180,7 +180,7 @@ func (k Keeper) IterateApplicationLinks(ctx sdk.Context, fn func(index int64, ap
 	}
 }
 
-func (k Keeper) IterateApplicationLinkClientIDs(ctx sdk.Context, fn func(index int64, clientID string, value []byte) (stop bool)) {
+func (k Keeper) IterateApplicationLinkClientIDKeys(ctx sdk.Context, fn func(index int64, key []byte, value []byte) (stop bool)) {
 	store := ctx.KVStore(k.storeKey)
 
 	clientIDsStore := prefix.NewStore(store, ApplicationLinkClientIDPrefix)
@@ -190,7 +190,7 @@ func (k Keeper) IterateApplicationLinkClientIDs(ctx sdk.Context, fn func(index i
 	var stop = false
 	var index = int64(0)
 	for ; iterator.Valid() && !stop; iterator.Next() {
-		stop = fn(index, string(iterator.Key()), iterator.Value())
+		stop = fn(index, append(ApplicationLinkClientIDPrefix, iterator.Key()...), iterator.Value())
 		index++
 	}
 }
diff --git a/x/profiles/legacy/v4/store.go b/x/profiles/legacy/v4/store.go
index 0b9bd827..424a67a9 100644
--- a/x/profiles/legacy/v4/store.go
+++ b/x/profiles/legacy/v4/store.go
@@ -38,7 +38,6 @@ func MigrateStore(ctx sdk.Context, ak authkeeper.AccountKeeper, storeKey sdk.Sto
 	migrateDTags(ctx, legacyKeeper, storeKey)
 	migrateDTagTransferRequests(ctx, legacyKeeper, storeKey, cdc)
 	migrateApplicationLinks(ctx, legacyKeeper, storeKey, cdc)
-	migrateApplicationLinksClientIDs(ctx, legacyKeeper, storeKey)
 
 	// Migrate the chain links
 	err = migrateChainLinks(ctx, legacyKeeper, storeKey, amino, cdc)
@@ -119,39 +118,34 @@ func migrateDTagTransferRequests(ctx sdk.Context, k Keeper, storeKey sdk.StoreKe
 }
 
 func migrateApplicationLinks(ctx sdk.Context, k Keeper, storeKey sdk.StoreKey, cdc codec.BinaryCodec) {
+	store := ctx.KVStore(storeKey)
+
 	var applicationLinks []types.ApplicationLink
 	k.IterateApplicationLinks(ctx, func(index int64, applicationLink types.ApplicationLink) (stop bool) {
 		applicationLinks = append(applicationLinks, applicationLink)
 		return false
 	})
 
-	store := ctx.KVStore(storeKey)
-	for i, link := range applicationLinks {
-		// Delete the old key
-		store.Delete(UserApplicationLinkKey(link.User, link.Data.Application, link.Data.Username))
-
-		// Store the link with the new key
-		store.Set(
-			types.UserApplicationLinkKey(link.User, link.Data.Application, link.Data.Username),
-			cdc.MustMarshal(&applicationLinks[i]),
-		)
-	}
-}
-
-func migrateApplicationLinksClientIDs(ctx sdk.Context, k Keeper, storeKey sdk.StoreKey) {
-	clientIDs := map[string][]byte{}
-	k.IterateApplicationLinkClientIDs(ctx, func(index int64, dTag string, value []byte) (stop bool) {
-		clientIDs[dTag] = value
+	var clientIDKeys [][]byte
+	k.IterateApplicationLinkClientIDKeys(ctx, func(index int64, key []byte, value []byte) (stop bool) {
+		clientIDKeys = append(clientIDKeys, key)
 		return false
 	})
 
-	store := ctx.KVStore(storeKey)
-	for clientID, value := range clientIDs {
-		// Delete the old key
-		store.Delete(ApplicationLinkClientIDKey(clientID))
+	// Delete all the client ID keys to make sure we remove leftover ones
+	// The new client ID keys will be set when storing the application links anyway later
+	for _, key := range clientIDKeys {
+		store.Delete(key)
+	}
 
-		// Store the client id using the new key
-		store.Set(types.ApplicationLinkClientIDKey(clientID), value)
+	for i, link := range applicationLinks {
+		// Delete the old keys
+		store.Delete(UserApplicationLinkKey(link.User, link.Data.Application, link.Data.Username))
+
+		// Store the link with the new key
+		linkKey := types.UserApplicationLinkKey(link.User, link.Data.Application, link.Data.Username)
+		store.Set(linkKey, cdc.MustMarshal(&applicationLinks[i]))
+		store.Set(types.ApplicationLinkClientIDKey(link.OracleRequest.ClientID), linkKey)
 	}
 }
 


Test patch:
diff --git a/x/profiles/keeper/keeper_app_links_test.go b/x/profiles/keeper/keeper_app_links_test.go
index 6f3e4615..f4563ad4 100644
--- a/x/profiles/keeper/keeper_app_links_test.go
+++ b/x/profiles/keeper/keeper_app_links_test.go
@@ -312,15 +312,13 @@ func (suite *KeeperTestSuite) Test_GetApplicationLinkByClientID() {
 
 func (suite *KeeperTestSuite) Test_DeleteApplicationLink() {
 	testCases := []struct {
-		name        string
-		store       func(store sdk.Context)
-		user        string
-		application string
-		username    string
-		shouldErr   bool
+		name  string
+		store func(ctx sdk.Context)
+		link  types.ApplicationLink
+		check func(ctx sdk.Context)
 	}{
 		{
-			name: "wrong user returns error",
+			name: "different user does not delete link",
 			store: func(ctx sdk.Context) {
 				address := "cosmos10nsdxxdvy9qka3zv0lzw8z9cnu6kanld8jh773"
 				link := types.NewApplicationLink(
@@ -341,13 +339,29 @@ func (suite *KeeperTestSuite) Test_DeleteApplicationLink() {
 				err := suite.k.SaveApplicationLink(ctx, link)
 				suite.Require().NoError(err)
 			},
-			user:        "user",
-			application: "twitter",
-			username:    "twitteruser",
-			shouldErr:   true,
+			link: types.NewApplicationLink(
+				"cosmos1xvvggrlgjkhu4rva9j500rc52za2smxhluvftc",
+				types.NewData("twitter", "twitteruser"),
+				types.ApplicationLinkStateInitialized,
+				types.NewOracleRequest(
+					0,
+					1,
+					types.NewOracleRequestCallData("twitter", "calldata"),
+					"client_id",
+				),
+				nil,
+				time.Date(2020, 1, 1, 00, 00, 00, 000, time.UTC),
+			),
+			check: func(ctx sdk.Context) {
+				suite.Require().True(suite.k.HasApplicationLink(ctx,
+					"cosmos10nsdxxdvy9qka3zv0lzw8z9cnu6kanld8jh773",
+					"twitter",
+					"twitteruser",
+				))
+			},
 		},
 		{
-			name: "wrong application returns error",
+			name: "different application does not delete the link",
 			store: func(ctx sdk.Context) {
 				address := "cosmos10nsdxxdvy9qka3zv0lzw8z9cnu6kanld8jh773"
 				link := types.NewApplicationLink(
@@ -368,13 +382,29 @@ func (suite *KeeperTestSuite) Test_DeleteApplicationLink() {
 				err := suite.k.SaveApplicationLink(ctx, link)
 				suite.Require().NoError(err)
 			},
-			user:        "cosmos10nsdxxdvy9qka3zv0lzw8z9cnu6kanld8jh773",
-			application: "github",
-			username:    "twitteruser",
-			shouldErr:   true,
+			link: types.NewApplicationLink(
+				"cosmos10nsdxxdvy9qka3zv0lzw8z9cnu6kanld8jh773",
+				types.NewData("github", "twitteruser"),
+				types.ApplicationLinkStateInitialized,
+				types.NewOracleRequest(
+					0,
+					1,
+					types.NewOracleRequestCallData("twitter", "calldata"),
+					"client_id",
+				),
+				nil,
+				time.Date(2020, 1, 1, 00, 00, 00, 000, time.UTC),
+			),
+			check: func(ctx sdk.Context) {
+				suite.Require().True(suite.k.HasApplicationLink(ctx,
+					"cosmos10nsdxxdvy9qka3zv0lzw8z9cnu6kanld8jh773",
+					"twitter",
+					"twitteruser",
+				))
+			},
 		},
 		{
-			name: "wrong username returns error",
+			name: "different username does not delete the link",
 			store: func(ctx sdk.Context) {
 				address := "cosmos10nsdxxdvy9qka3zv0lzw8z9cnu6kanld8jh773"
 				link := types.NewApplicationLink(
@@ -395,10 +425,26 @@ func (suite *KeeperTestSuite) Test_DeleteApplicationLink() {
 				err := suite.k.SaveApplicationLink(ctx, link)
 				suite.Require().NoError(err)
 			},
-			user:        "cosmos10nsdxxdvy9qka3zv0lzw8z9cnu6kanld8jh773",
-			application: "twitter",
-			username:    "twitter-user",
-			shouldErr:   true,
+			link: types.NewApplicationLink(
+				"cosmos10nsdxxdvy9qka3zv0lzw8z9cnu6kanld8jh773",
+				types.NewData("twitter", "another-user"),
+				types.ApplicationLinkStateInitialized,
+				types.NewOracleRequest(
+					0,
+					1,
+					types.NewOracleRequestCallData("twitter", "calldata"),
+					"client_id",
+				),
+				nil,
+				time.Date(2020, 1, 1, 00, 00, 00, 000, time.UTC),
+			),
+			check: func(ctx sdk.Context) {
+				suite.Require().True(suite.k.HasApplicationLink(ctx,
+					"cosmos10nsdxxdvy9qka3zv0lzw8z9cnu6kanld8jh773",
+					"twitter",
+					"twitteruser",
+				))
+			},
 		},
 		{
 			name: "valid request deletes link",
@@ -422,10 +468,26 @@ func (suite *KeeperTestSuite) Test_DeleteApplicationLink() {
 				err := suite.k.SaveApplicationLink(ctx, link)
 				suite.Require().NoError(err)
 			},
-			user:        "cosmos10nsdxxdvy9qka3zv0lzw8z9cnu6kanld8jh773",
-			application: "twitter",
-			username:    "twitteruser",
-			shouldErr:   false,
+			link: types.NewApplicationLink(
+				"cosmos10nsdxxdvy9qka3zv0lzw8z9cnu6kanld8jh773",
+				types.NewData("twitter", "twitteruser"),
+				types.ApplicationLinkStateInitialized,
+				types.NewOracleRequest(
+					0,
+					1,
+					types.NewOracleRequestCallData("twitter", "calldata"),
+					"client_id",
+				),
+				nil,
+				time.Date(2020, 1, 1, 00, 00, 00, 000, time.UTC),
+			),
+			check: func(ctx sdk.Context) {
+				suite.Require().False(suite.k.HasApplicationLink(ctx,
+					"cosmos10nsdxxdvy9qka3zv0lzw8z9cnu6kanld8jh773",
+					"twitter",
+					"twitteruser",
+				))
+			},
 		},
 	}
 
@@ -437,15 +499,9 @@ func (suite *KeeperTestSuite) Test_DeleteApplicationLink() {
 				tc.store(ctx)
 			}
 
-			err := suite.k.DeleteApplicationLink(ctx, tc.user, tc.application, tc.username)
-			if tc.shouldErr {
-				suite.Require().Error(err)
-			} else {
-				suite.Require().NoError(err)
-
-				_, found, err := suite.k.GetApplicationLink(ctx, tc.user, tc.application, tc.username)
-				suite.Require().NoError(err)
-				suite.Require().False(found)
+			suite.k.DeleteApplicationLink(ctx, tc.link)
+			if tc.check != nil {
+				tc.check(ctx)
 			}
 		})
 	}
diff --git a/x/profiles/keeper/keeper_chain_links_test.go b/x/profiles/keeper/keeper_chain_links_test.go
index 8547e4b5..efcb2ef0 100644
--- a/x/profiles/keeper/keeper_chain_links_test.go
+++ b/x/profiles/keeper/keeper_chain_links_test.go
@@ -224,56 +224,138 @@ func (suite *KeeperTestSuite) TestKeeper_GetChainLink() {
 }
 
 func (suite *KeeperTestSuite) TestKeeper_DeleteChainLink() {
+	pubKey := `{"@type":"/cosmos.crypto.secp256k1.PubKey","key":"A6jN4EPjj8mHf722yjEaKaGdJpxnTR40pDvXlX1mni9C"}`
+
+	var any codectypes.Any
+	err := suite.cdc.UnmarshalJSON([]byte(pubKey), &any)
+	suite.Require().NoError(err)
+
+	var key cryptotypes.PubKey
+	err = suite.cdc.UnpackAny(&any, &key)
+	suite.Require().NoError(err)
+
+	// Generate source and destination key
+	ext := suite.GetRandomProfile()
+	sig := hex.EncodeToString(ext.Sign([]byte(ext.GetAddress().String())))
+	plainText := hex.EncodeToString([]byte(ext.GetAddress().String()))
+
 	testCases := []struct {
-		name      string
-		store     func(ctx sdk.Context)
-		owner     string
-		chainName string
-		address   string
-		shouldErr bool
+		name  string
+		store func(ctx sdk.Context)
+		link  types.ChainLink
+		check func(ctx sdk.Context)
 	}{
 		{
-			name:      "invalid owner address returns error",
-			owner:     "",
-			chainName: "cosmos",
-			address:   "cosmos1cjf97gpzwmaf30pzvaargfgr884mpp5ak8f7ns",
-			shouldErr: true,
+			name: "different user does not delete link",
+			store: func(ctx sdk.Context) {
+				suite.Require().NoError(suite.k.StoreProfile(ctx, testutil.ProfileFromAddr("cosmos19xz3mrvzvp9ymgmudhpukucg6668l5haakh04x")))
+				err = suite.k.SaveChainLink(ctx, types.NewChainLink(
+					"cosmos19xz3mrvzvp9ymgmudhpukucg6668l5haakh04x",
+					types.NewBech32Address(ext.GetAddress().String(), "cosmos"),
+					types.NewProof(ext.GetPubKey(), testutil.SingleSignatureProtoFromHex(sig), plainText),
+					types.NewChainConfig("cosmos"),
+					time.Date(2020, 1, 2, 00, 00, 00, 000, time.UTC),
+				))
+				suite.Require().NoError(err)
+			},
+			link: types.NewChainLink(
+				"cosmos1xvvggrlgjkhu4rva9j500rc52za2smxhluvftc",
+				types.NewBech32Address(ext.GetAddress().String(), "cosmos"),
+				types.NewProof(ext.GetPubKey(), testutil.SingleSignatureProtoFromHex(sig), plainText),
+				types.NewChainConfig("cosmos"),
+				time.Date(2020, 1, 2, 00, 00, 00, 000, time.UTC),
+			),
+			check: func(ctx sdk.Context) {
+				suite.Require().True(suite.k.HasChainLink(ctx,
+					"cosmos19xz3mrvzvp9ymgmudhpukucg6668l5haakh04x",
+					"cosmos",
+					ext.GetAddress().String(),
+				))
+			},
 		},
 		{
-			name:      "owner without profile returns error",
-			owner:     "cosmos1cjf97gpzwmaf30pzvaargfgr884mpp5ak8f7ns",
-			chainName: "cosmos",
-			address:   "cosmos1cjf97gpzwmaf30pzvaargfgr884mpp5ak8f7ns",
-			shouldErr: true,
+			name: "different chain name does not delete link",
+			store: func(ctx sdk.Context) {
+				suite.Require().NoError(suite.k.StoreProfile(ctx, testutil.ProfileFromAddr("cosmos19xz3mrvzvp9ymgmudhpukucg6668l5haakh04x")))
+				err = suite.k.SaveChainLink(ctx, types.NewChainLink(
+					"cosmos19xz3mrvzvp9ymgmudhpukucg6668l5haakh04x",
+					types.NewBech32Address(ext.GetAddress().String(), "cosmos"),
+					types.NewProof(ext.GetPubKey(), testutil.SingleSignatureProtoFromHex(sig), plainText),
+					types.NewChainConfig("cosmos"),
+					time.Date(2020, 1, 2, 00, 00, 00, 000, time.UTC),
+				))
+				suite.Require().NoError(err)
+			},
+			link: types.NewChainLink(
+				"cosmos19xz3mrvzvp9ymgmudhpukucg6668l5haakh04x",
+				types.NewBech32Address(ext.GetAddress().String(), "cosmos"),
+				types.NewProof(ext.GetPubKey(), testutil.SingleSignatureProtoFromHex(sig), plainText),
+				types.NewChainConfig("likecoin"),
+				time.Date(2020, 1, 2, 00, 00, 00, 000, time.UTC),
+			),
+			check: func(ctx sdk.Context) {
+				suite.Require().True(suite.k.HasChainLink(ctx,
+					"cosmos19xz3mrvzvp9ymgmudhpukucg6668l5haakh04x",
+					"cosmos",
+					ext.GetAddress().String(),
+				))
+			},
 		},
 		{
-			name: "target address not linked to the profile returns error",
+			name: "different external address does not delete the link",
 			store: func(ctx sdk.Context) {
-				user := "cosmos10nsdxxdvy9qka3zv0lzw8z9cnu6kanld8jh773"
-				suite.Require().NoError(suite.k.StoreProfile(ctx, testutil.ProfileFromAddr(user)))
+				suite.Require().NoError(suite.k.StoreProfile(ctx, testutil.ProfileFromAddr("cosmos19xz3mrvzvp9ymgmudhpukucg6668l5haakh04x")))
+				err = suite.k.SaveChainLink(ctx, types.NewChainLink(
+					"cosmos19xz3mrvzvp9ymgmudhpukucg6668l5haakh04x",
+					types.NewBech32Address(ext.GetAddress().String(), "cosmos"),
+					types.NewProof(ext.GetPubKey(), testutil.SingleSignatureProtoFromHex(sig), plainText),
+					types.NewChainConfig("cosmos"),
+					time.Date(2020, 1, 2, 00, 00, 00, 000, time.UTC),
+				))
+				suite.Require().NoError(err)
+			},
+			link: types.NewChainLink(
+				"cosmos19xz3mrvzvp9ymgmudhpukucg6668l5haakh04x",
+				types.NewBech32Address("cosmos1xvvggrlgjkhu4rva9j500rc52za2smxhluvftc", "cosmos"),
+				types.NewProof(ext.GetPubKey(), testutil.SingleSignatureProtoFromHex(sig), plainText),
+				types.NewChainConfig("cosmos"),
+				time.Date(2020, 1, 2, 00, 00, 00, 000, time.UTC),
+			),
+			check: func(ctx sdk.Context) {
+				suite.Require().True(suite.k.HasChainLink(ctx,
+					"cosmos19xz3mrvzvp9ymgmudhpukucg6668l5haakh04x",
+					"cosmos",
+					ext.GetAddress().String(),
+				))
 			},
-			owner:     "cosmos10nsdxxdvy9qka3zv0lzw8z9cnu6kanld8jh773",
-			chainName: "cosmos",
-			address:   "cosmos1cjf97gpzwmaf30pzvaargfgr884mpp5ak8f7ns",
-			shouldErr: true,
 		},
 		{
-			name: "valid request returns no error",
+			name: "proper data delete the link",
 			store: func(ctx sdk.Context) {
-				// Store profile
-				user := "cosmos10nsdxxdvy9qka3zv0lzw8z9cnu6kanld8jh773"
-				profile := testutil.ProfileFromAddr(user)
-				suite.Require().NoError(suite.k.StoreProfile(ctx, profile))
-
-				// Store link
-				store := ctx.KVStore(suite.storeKey)
-				key := types.ChainLinksStoreKey(user, "cosmos", "cosmos1cjf97gpzwmaf30pzvaargfgr884mpp5ak8f7ns")
-				store.Set(key, profile.GetAddress())
+				suite.Require().NoError(suite.k.StoreProfile(ctx, testutil.ProfileFromAddr("cosmos19xz3mrvzvp9ymgmudhpukucg6668l5haakh04x")))
+				err = suite.k.SaveChainLink(ctx, types.NewChainLink(
+					"cosmos19xz3mrvzvp9ymgmudhpukucg6668l5haakh04x",
+					types.NewBech32Address(ext.GetAddress().String(), "cosmos"),
+					types.NewProof(ext.GetPubKey(), testutil.SingleSignatureProtoFromHex(sig), plainText),
+					types.NewChainConfig("cosmos"),
+					time.Date(2020, 1, 2, 00, 00, 00, 000, time.UTC),
+				))
+				suite.Require().NoError(err)
+			},
+			link: types.NewChainLink(
+				"cosmos19xz3mrvzvp9ymgmudhpukucg6668l5haakh04x",
+				types.NewBech32Address(ext.GetAddress().String(), "cosmos"),
+				types.NewProof(ext.GetPubKey(), testutil.SingleSignatureProtoFromHex(sig), plainText),
+				types.NewChainConfig("cosmos"),
+				time.Date(2020, 1, 2, 00, 00, 00, 000, time.UTC),
+			),
+			check: func(ctx sdk.Context) {
+				suite.Require().False(suite.k.HasChainLink(ctx,
+					"cosmos19xz3mrvzvp9ymgmudhpukucg6668l5haakh04x",
+					"cosmos",
+					ext.GetAddress().String(),
+				))
 			},
-			owner:     "cosmos10nsdxxdvy9qka3zv0lzw8z9cnu6kanld8jh773",
-			chainName: "cosmos",
-			address:   "cosmos1cjf97gpzwmaf30pzvaargfgr884mpp5ak8f7ns",
-			shouldErr: false,
 		},
 	}
 
@@ -285,14 +367,9 @@ func (suite *KeeperTestSuite) TestKeeper_DeleteChainLink() {
 				tc.store(ctx)
 			}
 
-			err := suite.k.DeleteChainLink(ctx, tc.owner, tc.chainName, tc.address)
-			if tc.shouldErr {
-				suite.Require().Error(err)
-			} else {
-				suite.Require().NoError(err)
-
-				_, found := suite.k.GetChainLink(ctx, tc.owner, tc.chainName, tc.address)
-				suite.Require().False(found)
+			suite.k.DeleteChainLink(ctx, tc.link)
+			if tc.check != nil {
+				tc.check(ctx)
 			}
 		})
 	}
diff --git a/x/profiles/keeper/keeper_dtag_transfers_test.go b/x/profiles/keeper/keeper_dtag_transfers_test.go
index 925a954c..d87b39ae 100644
--- a/x/profiles/keeper/keeper_dtag_transfers_test.go
+++ b/x/profiles/keeper/keeper_dtag_transfers_test.go
@@ -270,15 +270,14 @@ func (suite *KeeperTestSuite) TestKeeper_GetDTagTransferRequests() {
 
 func (suite *KeeperTestSuite) TestKeeper_DeleteDTagTransferRequest() {
 	testCases := []struct {
-		name      string
-		store     func(ctx sdk.Context)
-		sender    string
-		receiver  string
-		shouldErr bool
-		check     func(ctx sdk.Context)
+		name     string
+		store    func(ctx sdk.Context)
+		sender   string
+		receiver string
+		check    func(ctx sdk.Context)
 	}{
 		{
-			name: "deleting non existent request returns an error",
+			name: "deleting non existent request works properly",
 			store: func(ctx sdk.Context) {
 				request := types.NewDTagTransferRequest(
 					"dtag",
@@ -288,9 +287,8 @@ func (suite *KeeperTestSuite) TestKeeper_DeleteDTagTransferRequest() {
 				suite.Require().NoError(suite.k.StoreProfile(ctx, testutil.ProfileFromAddr(request.Receiver)))
 				suite.Require().NoError(suite.k.SaveDTagTransferRequest(ctx, request))
 			},
-			sender:    "cosmos1y54exmx84cqtasvjnskf9f63djuuj68p7hqf47",
-			receiver:  "cosmos1cjf97gpzwmaf30pzvaargfgr884mpp5ak8f7ns",
-			shouldErr: true,
+			sender:   "cosmos1y54exmx84cqtasvjnskf9f63djuuj68p7hqf47",
+			receiver: "cosmos1cjf97gpzwmaf30pzvaargfgr884mpp5ak8f7ns",
 		},
 		{
 			name: "existing request is removed properly",
@@ -319,15 +317,9 @@ func (suite *KeeperTestSuite) TestKeeper_DeleteDTagTransferRequest() {
 				tc.store(ctx)
 			}
 
-			err := suite.k.DeleteDTagTransferRequest(ctx, tc.sender, tc.receiver)
-
-			if tc.shouldErr {
-				suite.Require().Error(err)
-			} else {
-				suite.Require().NoError(err)
-				if tc.check != nil {
-					tc.check(ctx)
-				}
+			suite.k.DeleteDTagTransferRequest(ctx, tc.sender, tc.receiver)
+			if tc.check != nil {
+				tc.check(ctx)
 			}
 		})
 	}
diff --git a/x/profiles/legacy/v4/store_test.go b/x/profiles/legacy/v4/store_test.go
index 04542233..37469ba5 100644
--- a/x/profiles/legacy/v4/store_test.go
+++ b/x/profiles/legacy/v4/store_test.go
@@ -180,8 +180,9 @@ func TestMigrateStore(t *testing.T) {
 				kvStore := ctx.KVStore(keys[types.StoreKey])
 
 				// Store an application link
+				linkKey := v4.UserApplicationLinkKey("cosmos10nsdxxdvy9qka3zv0lzw8z9cnu6kanld8jh773", "twitter", "twitteruser")
 				kvStore.Set(
-					v4.UserApplicationLinkKey("cosmos10nsdxxdvy9qka3zv0lzw8z9cnu6kanld8jh773", "twitter", "twitteruser"),
+					linkKey,
 					cdc.MustMarshal(&profilestypes.ApplicationLink{
 						User:  "cosmos10nsdxxdvy9qka3zv0lzw8z9cnu6kanld8jh773",
 						Data:  profilestypes.NewData("twitter", "twitteruser"),
@@ -198,21 +199,20 @@ func TestMigrateStore(t *testing.T) {
 				)
 
 				// Store an application link client id
-				kvStore.Set(
-					v4.ApplicationLinkClientIDKey("client_id"),
-					[]byte("client_id_value"),
-				)
+				kvStore.Set(v4.ApplicationLinkClientIDKey("client_id"), linkKey)
 			},
 			check: func(ctx sdk.Context) {
 				kvStore := ctx.KVStore(keys[types.StoreKey])
 
 				// Check the application links
-				var stored profilestypes.ApplicationLink
-				cdc.MustUnmarshal(kvStore.Get(profilestypes.UserApplicationLinkKey(
+				linkKey := profilestypes.UserApplicationLinkKey(
 					"cosmos10nsdxxdvy9qka3zv0lzw8z9cnu6kanld8jh773",
 					"twitter",
 					"twitteruser",
-				)), &stored)
+				)
+
+				var stored profilestypes.ApplicationLink
+				cdc.MustUnmarshal(kvStore.Get(linkKey), &stored)
 				require.Equal(t, profilestypes.NewApplicationLink(
 					"cosmos10nsdxxdvy9qka3zv0lzw8z9cnu6kanld8jh773",
 					profilestypes.NewData("twitter", "twitteruser"),
@@ -228,7 +228,19 @@ func TestMigrateStore(t *testing.T) {
 				), stored)
 
 				// Check the application link client id
-				require.Equal(t, []byte("client_id_value"), kvStore.Get(profilestypes.ApplicationLinkClientIDKey("client_id")))
+				require.Equal(t, linkKey, kvStore.Get(profilestypes.ApplicationLinkClientIDKey("client_id")))
+			},
+		},
+		{
+			name: "leftover application client id keys are deleted properly",
+			store: func(ctx sdk.Context) {
+				kvStore := ctx.KVStore(keys[types.StoreKey])
+				kvStore.Set(v4.ApplicationLinkClientIDKey("client_id"), []byte("client_id_value"))
+			},
+			check: func(ctx sdk.Context) {
+				kvStore := ctx.KVStore(keys[types.StoreKey])
+				require.False(t, kvStore.Has(v4.ApplicationLinkClientIDKey("client_id")))
+				require.False(t, kvStore.Has(profilestypes.ApplicationLinkClientIDKey("client_id")))
 			},
 		},
 		{