Repository: desmos-labs/desmos
Pull request #842 (2022-04-26 06:38:32)

fix: fixed x/fees query endpoints
## Description

This PR fixes the `/desmos/fees/v1/fees/params` query endpoints to be `/desmos/fees/v1/params` removing the duplicated `/fees` part.

<!-- Add a description of the changes that this PR introduces and the files that
are the most critical to review. -->

---

### 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
- [x] 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)
- [ ] 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...

- [x] 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
- [x] confirmed all author checklist items have been addressed
- [ ] reviewed state machine logic
- [ ] reviewed API design and naming
- [ ] reviewed documentation is accurate
- [x] reviewed tests and test coverage
- [ ] manually tested (if applicable)

codecov[bot]: # [Codecov](https://codecov.io/gh/desmos-labs/desmos/pull/842?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=desmos-labs) Report
> Merging [#842](https://codecov.io/gh/desmos-labs/desmos/pull/842?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=desmos-labs) (55f7652) into [master](https://codecov.io/gh/desmos-labs/desmos/commit/c6847685f83f4da2aa99d1d99923e7f995b998f4?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=desmos-labs) (c684768) will **not change** coverage.
> The diff coverage is `n/a`.

```diff
@@           Coverage Diff           @@
##           master     #842   +/-   ##
=======================================
  Coverage   81.53%   81.53%           
=======================================
  Files          89       89           
  Lines        7018     7018           
=======================================
  Hits         5722     5722           
  Misses       1035     1035           
  Partials      261      261           
```



------

[Continue to review full report at Codecov](https://codecov.io/gh/desmos-labs/desmos/pull/842?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/842?src=pr&el=footer&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=desmos-labs). Last update [7ef1a5b...55f7652](https://codecov.io/gh/desmos-labs/desmos/pull/842?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/68d07218bf30b0b984be4c29146eb71f915df11721ab81b8eec2595ab493ae4d.yaml b/.changeset/entries/68d07218bf30b0b984be4c29146eb71f915df11721ab81b8eec2595ab493ae4d.yaml
new file mode 100644
index 00000000..9dfe3962
--- /dev/null
+++ b/.changeset/entries/68d07218bf30b0b984be4c29146eb71f915df11721ab81b8eec2595ab493ae4d.yaml
@@ -0,0 +1,6 @@
+type: fix
+module: x/profiles
+pull_request: 840
+description: Added missing profiles query commands
+backward_compatible: true
+date: 2022-04-25T09:33:37.0662913Z
diff --git a/.changeset/entries/6f0a061bd4ae3038eb8a5a71d9a3b1e6b88397a4e785bda00fec5fbd8bd0737b.yaml b/.changeset/entries/6f0a061bd4ae3038eb8a5a71d9a3b1e6b88397a4e785bda00fec5fbd8bd0737b.yaml
new file mode 100644
index 00000000..f0add99b
--- /dev/null
+++ b/.changeset/entries/6f0a061bd4ae3038eb8a5a71d9a3b1e6b88397a4e785bda00fec5fbd8bd0737b.yaml
@@ -0,0 +1,6 @@
+type: fix
+module: x/relationships
+pull_request: 838
+description: Replaced store keys to use less disk space
+backward_compatible: false
+date: 2022-04-22T12:01:24.865079216Z
diff --git a/.changeset/entries/8fea7719728d408975e08ec2ca629f6241c68afe263cc5897d7ebcb0856b4520.yaml b/.changeset/entries/8fea7719728d408975e08ec2ca629f6241c68afe263cc5897d7ebcb0856b4520.yaml
new file mode 100644
index 00000000..bad9b00f
--- /dev/null
+++ b/.changeset/entries/8fea7719728d408975e08ec2ca629f6241c68afe263cc5897d7ebcb0856b4520.yaml
@@ -0,0 +1,6 @@
+type: fix
+module: x/profiles
+pull_request: 832
+description: Fixed the CLI commands expected number of arguments
+backward_compatible: true
+date: 2022-04-22T05:53:09.198350555Z
diff --git a/.changeset/entries/bc776b2301982eaae47a6da9ac287a76dace06b0cb1cab882868d56c021dffdc.yaml b/.changeset/entries/bc776b2301982eaae47a6da9ac287a76dace06b0cb1cab882868d56c021dffdc.yaml
new file mode 100644
index 00000000..abf52d9f
--- /dev/null
+++ b/.changeset/entries/bc776b2301982eaae47a6da9ac287a76dace06b0cb1cab882868d56c021dffdc.yaml
@@ -0,0 +1,6 @@
+type: fix
+module: other
+pull_request: 829
+description: Added missing events and events attributes
+backward_compatible: true
+date: 2022-04-21T07:31:55.785338327Z
diff --git a/.changeset/entries/fc7708b5917c157edbbc96281bba1a63928dd2becf8fd057cd3d9592a88f1798.yaml b/.changeset/entries/fc7708b5917c157edbbc96281bba1a63928dd2becf8fd057cd3d9592a88f1798.yaml
new file mode 100644
index 00000000..59e2d2ee
--- /dev/null
+++ b/.changeset/entries/fc7708b5917c157edbbc96281bba1a63928dd2becf8fd057cd3d9592a88f1798.yaml
@@ -0,0 +1,6 @@
+type: fix
+module: x/profiles
+pull_request: 831
+description: Renamed the `dtag_transfer_requests` REST endpoint to `dtag-transfer-requests`
+backward_compatible: false
+date: 2022-04-22T05:44:24.874087179Z
diff --git a/client/docs/swagger-ui/swagger.yaml b/client/docs/swagger-ui/swagger.yaml
index 6d97753a..705ee85a 100644
--- a/client/docs/swagger-ui/swagger.yaml
+++ b/client/docs/swagger-ui/swagger.yaml
@@ -2329,7 +2329,7 @@ paths:
           format: boolean
       tags:
         - Query
-  /desmos/profiles/v2/dtag_transfer_requests:
+  /desmos/profiles/v2/dtag-transfer-requests:
     get:
       summary: >-
         IncomingDTagTransferRequests queries all the DTag transfers requests
diff --git a/proto/desmos/fees/v1/query.proto b/proto/desmos/fees/v1/query.proto
index b90ec41b..e007edb3 100644
--- a/proto/desmos/fees/v1/query.proto
+++ b/proto/desmos/fees/v1/query.proto
@@ -11,7 +11,7 @@ option go_package = "github.com/desmos-labs/desmos/v3/x/fees/types";
 service Query {
   // Params queries the fees module params
   rpc Params(QueryParamsRequest) returns (QueryParamsResponse) {
-    option (google.api.http).get = "/desmos/fees/v1/fees/params";
+    option (google.api.http).get = "/desmos/fees/v1/params";
   }
 }
 
diff --git a/proto/desmos/profiles/v2/query.proto b/proto/desmos/profiles/v2/query.proto
index 7a5d7d3b..023aa98c 100644
--- a/proto/desmos/profiles/v2/query.proto
+++ b/proto/desmos/profiles/v2/query.proto
@@ -27,7 +27,7 @@ service Query {
   // have been made towards the user with the given address
   rpc IncomingDTagTransferRequests(QueryIncomingDTagTransferRequestsRequest)
       returns (QueryIncomingDTagTransferRequestsResponse) {
-    option (google.api.http).get = "/desmos/profiles/v2/dtag_transfer_requests";
+    option (google.api.http).get = "/desmos/profiles/v2/dtag-transfer-requests";
   }
 
   // ChainLinks queries the chain links associated to the given user, if
diff --git a/proto/desmos/supply/v1/query.proto b/proto/desmos/supply/v1/query.proto
index 86bede92..2985e932 100644
--- a/proto/desmos/supply/v1/query.proto
+++ b/proto/desmos/supply/v1/query.proto
@@ -10,20 +10,20 @@ import "cosmos/base/v1beta1/coin.proto";
 
 option go_package = "github.com/desmos-labs/desmos/v3/x/supply/types";
 
-
 // Query defines the gRPC querier service.
 service Query {
 
   // TotalSupply queries the total supply of the given denom
-  rpc TotalSupply(QueryTotalSupplyRequest)
-      returns (QueryTotalSupplyResponse) {
+  rpc TotalSupply(QueryTotalSupplyRequest) returns (QueryTotalSupplyResponse) {
     option (google.api.http).get = "/desmos/supply/v1/total-supply/{denom}";
   }
 
-  // CirculatingSupply queries the amount of tokens circulating in the market of the given denom
+  // CirculatingSupply queries the amount of tokens circulating in the market of
+  // the given denom
   rpc CirculatingSupply(QueryCirculatingSupplyRequest)
       returns (QueryCirculatingSupplyResponse) {
-    option (google.api.http).get = "/desmos/supply/v1/circulating-supply/{denom}";
+    option (google.api.http).get =
+        "/desmos/supply/v1/circulating-supply/{denom}";
   }
 }
 
@@ -35,11 +35,13 @@ message QueryTotalSupplyRequest {
   // coin denom to query the circulating supply for
   string denom = 1;
 
-  // divider_exponent is a factor used to power the divider used to convert the supply to the desired representation
+  // divider_exponent is a factor used to power the divider used to convert the
+  // supply to the desired representation
   uint64 divider_exponent = 2;
 }
 
-// QueryTotalSupplyResponse is the response type for the Query/TotalSupply RPC method
+// QueryTotalSupplyResponse is the response type for the Query/TotalSupply RPC
+// method
 message QueryTotalSupplyResponse {
   option (gogoproto.equal) = false;
   option (gogoproto.goproto_getters) = false;
@@ -50,7 +52,8 @@ message QueryTotalSupplyResponse {
   ];
 }
 
-// QueryCirculatingSupplyRequest is the request type for the Query/CirculatingSupply RPC method
+// QueryCirculatingSupplyRequest is the request type for the
+// Query/CirculatingSupply RPC method
 message QueryCirculatingSupplyRequest {
   option (gogoproto.equal) = false;
   option (gogoproto.goproto_getters) = false;
@@ -58,11 +61,13 @@ message QueryCirculatingSupplyRequest {
   // coin denom to query the circulating supply for
   string denom = 1;
 
-  // divider_exponent is a factor used to power the divider used to convert the supply to the desired representation
+  // divider_exponent is a factor used to power the divider used to convert the
+  // supply to the desired representation
   uint64 divider_exponent = 2;
 }
 
-// QueryCirculatingSupplyRequest is the response type for the Query/CirculatingSupply RPC method
+// QueryCirculatingSupplyRequest is the response type for the
+// Query/CirculatingSupply RPC method
 message QueryCirculatingSupplyResponse {
   option (gogoproto.equal) = false;
   option (gogoproto.goproto_getters) = false;
diff --git a/x/fees/types/params.go b/x/fees/types/params.go
index 82d41f1b..77a321dc 100644
--- a/x/fees/types/params.go
+++ b/x/fees/types/params.go
@@ -60,7 +60,21 @@ func ValidateMinFeesParam(i interface{}) error {
 		if err := fee.Validate(); err != nil {
 			return err
 		}
+
+		if isMinFeeDuplicated(fee, fees) {
+			return fmt.Errorf("duplicated min fee for message type %s", fee.MessageType)
+		}
 	}
 
 	return nil
 }
+
+func isMinFeeDuplicated(value MinFee, minFees []MinFee) bool {
+	var count = 0
+	for _, fee := range minFees {
+		if fee.MessageType == value.MessageType {
+			count++
+		}
+	}
+	return count > 1
+}
diff --git a/x/fees/types/query.pb.go b/x/fees/types/query.pb.go
index 6bceef53..2d0bcd6d 100644
--- a/x/fees/types/query.pb.go
+++ b/x/fees/types/query.pb.go
@@ -119,7 +119,7 @@ func init() {
 func init() { proto.RegisterFile("desmos/fees/v1/query.proto", fileDescriptor_c487b62247198b65) }
 
 var fileDescriptor_c487b62247198b65 = []byte{
-	// 277 bytes of a gzipped FileDescriptorProto
+	// 273 bytes of a gzipped FileDescriptorProto
 	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0x4a, 0x49, 0x2d, 0xce,
 	0xcd, 0x2f, 0xd6, 0x4f, 0x4b, 0x4d, 0x2d, 0xd6, 0x2f, 0x33, 0xd4, 0x2f, 0x2c, 0x4d, 0x2d, 0xaa,
 	0xd4, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0xe2, 0x83, 0xc8, 0xe9, 0x81, 0xe4, 0xf4, 0xca, 0x0c,
@@ -129,15 +129,15 @@ var fileDescriptor_c487b62247198b65 = []byte{
 	0xa4, 0x92, 0x08, 0x97, 0x50, 0x20, 0xc8, 0xbe, 0x00, 0xb0, 0x60, 0x50, 0x6a, 0x61, 0x69, 0x6a,
 	0x71, 0x89, 0x92, 0x37, 0x97, 0x30, 0x8a, 0x68, 0x71, 0x41, 0x7e, 0x5e, 0x71, 0xaa, 0x90, 0x09,
 	0x17, 0x1b, 0x44, 0xb3, 0x04, 0xa3, 0x02, 0xa3, 0x06, 0xb7, 0x91, 0x98, 0x1e, 0xaa, 0xf3, 0xf4,
-	0x20, 0xea, 0x9d, 0x58, 0x4e, 0xdc, 0x93, 0x67, 0x08, 0x82, 0xaa, 0x35, 0xaa, 0xe7, 0x62, 0x05,
-	0x1b, 0x26, 0x54, 0xc6, 0xc5, 0x06, 0x51, 0x20, 0xa4, 0x84, 0xae, 0x11, 0xd3, 0x0d, 0x52, 0xca,
-	0x78, 0xd5, 0x40, 0x5c, 0xa4, 0xa4, 0xdc, 0x74, 0xf9, 0xc9, 0x64, 0x26, 0x59, 0x21, 0x69, 0x7d,
-	0x34, 0x4f, 0x82, 0x69, 0x88, 0x03, 0x9c, 0xdc, 0x4f, 0x3c, 0x92, 0x63, 0xbc, 0xf0, 0x48, 0x8e,
-	0xf1, 0xc1, 0x23, 0x39, 0xc6, 0x09, 0x8f, 0xe5, 0x18, 0x2e, 0x3c, 0x96, 0x63, 0xb8, 0xf1, 0x58,
-	0x8e, 0x21, 0x4a, 0x37, 0x3d, 0xb3, 0x24, 0xa3, 0x34, 0x49, 0x2f, 0x39, 0x3f, 0x17, 0x6a, 0x80,
-	0x6e, 0x4e, 0x62, 0x52, 0x31, 0xcc, 0xb0, 0x32, 0x63, 0xfd, 0x0a, 0x88, 0x49, 0x25, 0x95, 0x05,
-	0xa9, 0xc5, 0x49, 0x6c, 0xe0, 0x30, 0x33, 0x06, 0x04, 0x00, 0x00, 0xff, 0xff, 0xbd, 0x70, 0x0d,
-	0x89, 0xb2, 0x01, 0x00, 0x00,
+	0x20, 0xea, 0x9d, 0x58, 0x4e, 0xdc, 0x93, 0x67, 0x08, 0x82, 0xaa, 0x35, 0xaa, 0xe2, 0x62, 0x05,
+	0x1b, 0x26, 0x54, 0xc8, 0xc5, 0x06, 0x51, 0x20, 0xa4, 0x84, 0xae, 0x11, 0xd3, 0x0d, 0x52, 0xca,
+	0x78, 0xd5, 0x40, 0x5c, 0xa4, 0x24, 0xd7, 0x74, 0xf9, 0xc9, 0x64, 0x26, 0x09, 0x21, 0x31, 0x7d,
+	0xac, 0x9e, 0x74, 0x72, 0x3f, 0xf1, 0x48, 0x8e, 0xf1, 0xc2, 0x23, 0x39, 0xc6, 0x07, 0x8f, 0xe4,
+	0x18, 0x27, 0x3c, 0x96, 0x63, 0xb8, 0xf0, 0x58, 0x8e, 0xe1, 0xc6, 0x63, 0x39, 0x86, 0x28, 0xdd,
+	0xf4, 0xcc, 0x92, 0x8c, 0xd2, 0x24, 0xbd, 0xe4, 0xfc, 0x5c, 0xa8, 0x5e, 0xdd, 0x9c, 0xc4, 0xa4,
+	0x62, 0x98, 0x39, 0x65, 0xc6, 0xfa, 0x15, 0x10, 0xc3, 0x4a, 0x2a, 0x0b, 0x52, 0x8b, 0x93, 0xd8,
+	0xc0, 0xc1, 0x65, 0x0c, 0x08, 0x00, 0x00, 0xff, 0xff, 0x92, 0x37, 0x07, 0x94, 0xad, 0x01, 0x00,
+	0x00,
 }
 
 // Reference imports to suppress errors if they are not otherwise used.
diff --git a/x/fees/types/query.pb.gw.go b/x/fees/types/query.pb.gw.go
index fc3d0571..a8fdd4b1 100644
--- a/x/fees/types/query.pb.gw.go
+++ b/x/fees/types/query.pb.gw.go
@@ -140,7 +140,7 @@ func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie
 }
 
 var (
-	pattern_Query_Params_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 1, 2, 3}, []string{"desmos", "fees", "v1", "params"}, "", runtime.AssumeColonVerbOpt(true)))
+	pattern_Query_Params_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"desmos", "fees", "v1", "params"}, "", runtime.AssumeColonVerbOpt(true)))
 )
 
 var (
diff --git a/x/profiles/client/cli/cli_app_links.go b/x/profiles/client/cli/cli_app_links.go
index b0d1ee7e..c4f0b6ef 100644
--- a/x/profiles/client/cli/cli_app_links.go
+++ b/x/profiles/client/cli/cli_app_links.go
@@ -143,8 +143,8 @@ func GetCmdQueryApplicationsLinks() *cobra.Command {
 		Short: "Get all the application links with optional user address, application, username and pagination",
 		Example: fmt.Sprintf(`%s query profiles app-links --page=2 --limit=100
 %s query profiles app-links desmos13p5pamrljhza3fp4es5m3llgmnde5fzcpq6nud
-%s query app-links desmos13p5pamrljhza3fp4es5m3llgmnde5fzcpq6nud "twitter"
-%s query app-links desmos13p5pamrljhza3fp4es5m3llgmnde5fzcpq6nud "twitter" "twitter_user"
+%s query profiles app-links desmos13p5pamrljhza3fp4es5m3llgmnde5fzcpq6nud "twitter"
+%s query profiles app-links desmos13p5pamrljhza3fp4es5m3llgmnde5fzcpq6nud "twitter" "twitter_user"
 `, version.AppName, version.AppName, version.AppName, version.AppName),
 		Args: cobra.RangeArgs(0, 3),
 		RunE: func(cmd *cobra.Command, args []string) error {
@@ -191,3 +191,53 @@ func GetCmdQueryApplicationsLinks() *cobra.Command {
 
 	return cmd
 }
+
+// GetCmdQueryApplicationLinkOwners returns the command allowing to query the application link owners, optionally associated with a target
+func GetCmdQueryApplicationLinkOwners() *cobra.Command {
+	cmd := &cobra.Command{
+		Use:   "app-link-owners [[application]] [[username]]",
+		Short: "Get all the application link owners with optional application, username and pagination",
+		Example: fmt.Sprintf(`%s query profiles app-link-owners --page=2 --limit=100
+%s query profiles app-link-owners "twitter"
+%s query profiles app-link-owners "twitter" "twitter_user"
+`, version.AppName, version.AppName, version.AppName),
+		Args: cobra.RangeArgs(0, 2),
+		RunE: func(cmd *cobra.Command, args []string) error {
+			clientCtx, err := client.GetClientQueryContext(cmd)
+			if err != nil {
+				return err
+			}
+			queryClient := types.NewQueryClient(clientCtx)
+
+			var application string
+			if len(args) > 0 {
+				application = args[0]
+			}
+
+			var username string
+			if len(args) > 1 {
+				username = args[1]
+			}
+
+			pageReq, err := client.ReadPageRequest(cmd.Flags())
+			if err != nil {
+				return err
+			}
+
+			res, err := queryClient.ApplicationLinkOwners(
+				context.Background(),
+				types.NewQueryApplicationLinkOwnersRequest(application, username, pageReq),
+			)
+			if err != nil {
+				return err
+			}
+
+			return clientCtx.PrintProto(res)
+		},
+	}
+
+	flags.AddQueryFlagsToCmd(cmd)
+	flags.AddPaginationFlagsToCmd(cmd, "app link owners")
+
+	return cmd
+}
diff --git a/x/profiles/client/cli/cli_chain_links.go b/x/profiles/client/cli/cli_chain_links.go
index 4546db45..0bc5594e 100644
--- a/x/profiles/client/cli/cli_chain_links.go
+++ b/x/profiles/client/cli/cli_chain_links.go
@@ -26,7 +26,7 @@ func GetCmdLinkChainAccount() *cobra.Command {
 The link data must be supplied via a JSON file.
 
 Example:
-$ %s tx profiles link <path/to/data.json> --from=<key_or_address>
+$ %s tx profiles link-chain <path/to/data.json> --from=<key_or_address>
 
 Where data.json contains:
 
@@ -115,13 +115,13 @@ func GetCmdQueryChainLinks() *cobra.Command {
 	cmd := &cobra.Command{
 		Use:   "chain-links [[user]] [[chain_name]] [[target]]",
 		Short: "Retrieve all chain links with optional user address, chain name, target and pagination",
-		Example: fmt.Sprintf(`%s query chain-links chain-links
-%s query chain-links chain-links --page=2 --limit=100
+		Example: fmt.Sprintf(`%s query profiles chain-links
+%s query profiles chain-links --page=2 --limit=100
 %s query profiles chain-links desmos13p5pamrljhza3fp4es5m3llgmnde5fzcpq6nud
 %s query profiles chain-links desmos13p5pamrljhza3fp4es5m3llgmnde5fzcpq6nud "cosmos"
 %s query profiles chain-links desmos13p5pamrljhza3fp4es5m3llgmnde5fzcpq6nud "cosmos" cosmos19s242dxhxgzlsdmfjjg38jgfwhxca7569g84sw
 `, version.AppName, version.AppName, version.AppName, version.AppName, version.AppName),
-		Args: cobra.RangeArgs(0, 1),
+		Args: cobra.RangeArgs(0, 3),
 		RunE: func(cmd *cobra.Command, args []string) error {
 			clientCtx, err := client.GetClientQueryContext(cmd)
 			if err != nil {
@@ -166,3 +166,54 @@ func GetCmdQueryChainLinks() *cobra.Command {
 
 	return cmd
 }
+
+// GetCmdQueryChainLinkOwners returns the command allowing to query the chain link owners, optionally associated with a target
+func GetCmdQueryChainLinkOwners() *cobra.Command {
+	cmd := &cobra.Command{
+		Use:   "chain-link-owners [[chain_name]] [[target]]",
+		Short: "Retrieve all chain link owners with optional chain name, target and pagination",
+		Example: fmt.Sprintf(`%s query profiles chain-link-owners
+%s query profiles chain-link-owners --page=2 --limit=100
+%s query profiles chain-link-owners "cosmos"
+%s query profiles chain-link-owners "cosmos" cosmos19s242dxhxgzlsdmfjjg38jgfwhxca7569g84sw
+`, version.AppName, version.AppName, version.AppName, version.AppName),
+		Args: cobra.RangeArgs(0, 2),
+		RunE: func(cmd *cobra.Command, args []string) error {
+			clientCtx, err := client.GetClientQueryContext(cmd)
+			if err != nil {
+				return err
+			}
+			queryClient := types.NewQueryClient(clientCtx)
+
+			var chainName string
+			if len(args) > 0 {
+				chainName = args[0]
+			}
+
+			var target string
+			if len(args) > 1 {
+				target = args[1]
+			}
+
+			pageReq, err := client.ReadPageRequest(cmd.Flags())
+			if err != nil {
+				return err
+			}
+
+			res, err := queryClient.ChainLinkOwners(
+				context.Background(),
+				types.NewQueryChainLinkOwnersRequest(chainName, target, pageReq),
+			)
+			if err != nil {
+				return err
+			}
+
+			return clientCtx.PrintProto(res)
+		},
+	}
+
+	flags.AddPaginationFlagsToCmd(cmd, "chain link owners")
+	flags.AddQueryFlagsToCmd(cmd)
+
+	return cmd
+}
diff --git a/x/profiles/client/cli/cli_dtag_requests.go b/x/profiles/client/cli/cli_dtag_requests.go
index 89301149..bee877db 100644
--- a/x/profiles/client/cli/cli_dtag_requests.go
+++ b/x/profiles/client/cli/cli_dtag_requests.go
@@ -81,8 +81,10 @@ func GetCmdCancelDTagTransfer() *cobra.Command {
 // GetCmdAcceptDTagTransfer returns the command to accept a DTag transfer request
 func GetCmdAcceptDTagTransfer() *cobra.Command {
 	cmd := &cobra.Command{
-		Use: "accept-dtag-transfer-request [DTag] [address]",
-		Short: `Accept a DTag transfer request made by the user with the given address.
+		Use:   "accept-dtag-transfer-request [DTag] [address]",
+		Short: `Accept a DTag transfer request made by another user towards you`,
+		Long: `Accept a DTag transfer request made by the user with the given address.
+
 When accepting the request, you can specify the request recipient DTag as your new DTag. 
 If this happens, your DTag and the other user's one will be effectively swapped.`,
 		Example: fmt.Sprintf(`%s tx profiles accept-dtag-transfer-request "leoDiCaprio" desmos13p5pamrljhza3fp4es5m3llgmnde5fzcpq6nud`, version.AppName),
diff --git a/x/profiles/client/cli/query.go b/x/profiles/client/cli/query.go
index 48afcf1c..01e85452 100644
--- a/x/profiles/client/cli/query.go
+++ b/x/profiles/client/cli/query.go
@@ -24,7 +24,9 @@ func GetQueryCmd() *cobra.Command {
 		GetCmdQueryDTagRequests(),
 		GetCmdQueryParams(),
 		GetCmdQueryChainLinks(),
+		GetCmdQueryChainLinkOwners(),
 		GetCmdQueryApplicationsLinks(),
+		GetCmdQueryApplicationLinkOwners(),
 	)
 	return profileQueryCmd
 }
diff --git a/x/profiles/keeper/msg_server_app_link.go b/x/profiles/keeper/msg_server_app_link.go
index d842b421..36b093ab 100644
--- a/x/profiles/keeper/msg_server_app_link.go
+++ b/x/profiles/keeper/msg_server_app_link.go
@@ -50,6 +50,7 @@ func (k Keeper) LinkApplication(
 		sdk.NewEvent(
 			sdk.EventTypeMessage,
 			sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory),
+			sdk.NewAttribute(sdk.AttributeKeyAction, sdk.MsgTypeURL(msg)),
 			sdk.NewAttribute(sdk.AttributeKeySender, msg.Sender),
 		),
 		sdk.NewEvent(
@@ -91,6 +92,7 @@ func (k msgServer) UnlinkApplication(
 		sdk.NewEvent(
 			sdk.EventTypeMessage,
 			sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory),
+			sdk.NewAttribute(sdk.AttributeKeyAction, sdk.MsgTypeURL(msg)),
 			sdk.NewAttribute(sdk.AttributeKeySender, msg.Signer),
 		),
 		sdk.NewEvent(
diff --git a/x/profiles/keeper/msg_server_chain_link.go b/x/profiles/keeper/msg_server_chain_link.go
index 1b976a2f..bdb7d288 100644
--- a/x/profiles/keeper/msg_server_chain_link.go
+++ b/x/profiles/keeper/msg_server_chain_link.go
@@ -25,13 +25,21 @@ func (k msgServer) LinkChainAccount(goCtx context.Context, msg *types.MsgLinkCha
 		return nil, err
 	}
 
-	ctx.EventManager().EmitEvent(sdk.NewEvent(
-		types.EventTypeLinkChainAccount,
-		sdk.NewAttribute(types.AttributeKeyChainLinkSourceAddress, srcAddrData.GetValue()),
-		sdk.NewAttribute(types.AttributeKeyChainLinkSourceChainName, msg.ChainConfig.Name),
-		sdk.NewAttribute(types.AttributeKeyChainLinkDestinationAddress, msg.Signer),
-		sdk.NewAttribute(types.AttributeKeyChainLinkCreationTime, link.CreationTime.Format(time.RFC3339Nano)),
-	))
+	ctx.EventManager().EmitEvents(sdk.Events{
+		sdk.NewEvent(
+			sdk.EventTypeMessage,
+			sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory),
+			sdk.NewAttribute(sdk.AttributeKeyAction, sdk.MsgTypeURL(msg)),
+			sdk.NewAttribute(sdk.AttributeKeySender, msg.Signer),
+		),
+		sdk.NewEvent(
+			types.EventTypeLinkChainAccount,
+			sdk.NewAttribute(types.AttributeKeyChainLinkSourceAddress, srcAddrData.GetValue()),
+			sdk.NewAttribute(types.AttributeKeyChainLinkSourceChainName, msg.ChainConfig.Name),
+			sdk.NewAttribute(types.AttributeKeyChainLinkDestinationAddress, msg.Signer),
+			sdk.NewAttribute(types.AttributeKeyChainLinkCreationTime, link.CreationTime.Format(time.RFC3339Nano)),
+		),
+	})
 
 	return &types.MsgLinkChainAccountResponse{}, nil
 }
@@ -48,12 +56,20 @@ func (k msgServer) UnlinkChainAccount(goCtx context.Context, msg *types.MsgUnlin
 	// Delete the link
 	k.DeleteChainLink(ctx, link)
 
-	ctx.EventManager().EmitEvent(sdk.NewEvent(
-		types.EventTypeUnlinkChainAccount,
-		sdk.NewAttribute(types.AttributeKeyChainLinkSourceAddress, msg.Target),
-		sdk.NewAttribute(types.AttributeKeyChainLinkSourceChainName, msg.ChainName),
-		sdk.NewAttribute(types.AttributeKeyChainLinkDestinationAddress, msg.Owner),
-	))
+	ctx.EventManager().EmitEvents(sdk.Events{
+		sdk.NewEvent(
+			sdk.EventTypeMessage,
+			sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory),
+			sdk.NewAttribute(sdk.AttributeKeyAction, sdk.MsgTypeURL(msg)),
+			sdk.NewAttribute(sdk.AttributeKeySender, msg.Owner),
+		),
+		sdk.NewEvent(
+			types.EventTypeUnlinkChainAccount,
+			sdk.NewAttribute(types.AttributeKeyChainLinkSourceAddress, msg.Target),
+			sdk.NewAttribute(types.AttributeKeyChainLinkSourceChainName, msg.ChainName),
+			sdk.NewAttribute(types.AttributeKeyChainLinkDestinationAddress, msg.Owner),
+		),
+	})
 
 	return &types.MsgUnlinkChainAccountResponse{}, nil
 }
diff --git a/x/profiles/keeper/msg_server_dtag_transfers.go b/x/profiles/keeper/msg_server_dtag_transfers.go
index 63b5b8f9..f6b9843e 100644
--- a/x/profiles/keeper/msg_server_dtag_transfers.go
+++ b/x/profiles/keeper/msg_server_dtag_transfers.go
@@ -46,6 +46,7 @@ func (k msgServer) RequestDTagTransfer(goCtx context.Context, msg *types.MsgRequ
 		sdk.NewEvent(
 			sdk.EventTypeMessage,
 			sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory),
+			sdk.NewAttribute(sdk.AttributeKeyAction, sdk.MsgTypeURL(msg)),
 			sdk.NewAttribute(sdk.AttributeKeySender, msg.Sender),
 		),
 		sdk.NewEvent(
@@ -74,6 +75,7 @@ func (k msgServer) CancelDTagTransferRequest(goCtx context.Context, msg *types.M
 		sdk.NewEvent(
 			sdk.EventTypeMessage,
 			sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory),
+			sdk.NewAttribute(sdk.AttributeKeyAction, sdk.MsgTypeURL(msg)),
 			sdk.NewAttribute(sdk.AttributeKeySender, msg.Sender),
 		),
 		sdk.NewEvent(
@@ -178,6 +180,7 @@ func (k msgServer) AcceptDTagTransferRequest(goCtx context.Context, msg *types.M
 		sdk.NewEvent(
 			sdk.EventTypeMessage,
 			sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory),
+			sdk.NewAttribute(sdk.AttributeKeyAction, sdk.MsgTypeURL(msg)),
 			sdk.NewAttribute(sdk.AttributeKeySender, msg.Receiver),
 		),
 		sdk.NewEvent(
@@ -207,6 +210,7 @@ func (k msgServer) RefuseDTagTransferRequest(goCtx context.Context, msg *types.M
 		sdk.NewEvent(
 			sdk.EventTypeMessage,
 			sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory),
+			sdk.NewAttribute(sdk.AttributeKeyAction, sdk.MsgTypeURL(msg)),
 			sdk.NewAttribute(sdk.AttributeKeySender, msg.Receiver),
 		),
 		sdk.NewEvent(
diff --git a/x/profiles/keeper/msgs_server_profile.go b/x/profiles/keeper/msgs_server_profile.go
index cd02d541..5b75dd89 100644
--- a/x/profiles/keeper/msgs_server_profile.go
+++ b/x/profiles/keeper/msgs_server_profile.go
@@ -70,6 +70,7 @@ func (k msgServer) SaveProfile(goCtx context.Context, msg *types.MsgSaveProfile)
 		sdk.NewEvent(
 			sdk.EventTypeMessage,
 			sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory),
+			sdk.NewAttribute(sdk.AttributeKeyAction, sdk.MsgTypeURL(msg)),
 			sdk.NewAttribute(sdk.AttributeKeySender, msg.Creator),
 		),
 		sdk.NewEvent(
@@ -95,6 +96,7 @@ func (k msgServer) DeleteProfile(goCtx context.Context, msg *types.MsgDeleteProf
 		sdk.NewEvent(
 			sdk.EventTypeMessage,
 			sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory),
+			sdk.NewAttribute(sdk.AttributeKeyAction, sdk.MsgTypeURL(msg)),
 			sdk.NewAttribute(sdk.AttributeKeySender, msg.Creator),
 		),
 		sdk.NewEvent(
diff --git a/x/profiles/types/events.go b/x/profiles/types/events.go
index 598bccf8..3c77c25d 100644
--- a/x/profiles/types/events.go
+++ b/x/profiles/types/events.go
@@ -3,20 +3,20 @@ package types
 // DONTCOVER
 
 const (
-	EventTypeProfileSaved            = "profile_saved"
-	EventTypeProfileDeleted          = "profile_deleted"
-	EventTypeDTagTransferRequest     = "dtag_transfer_request"
-	EventTypeDTagTransferAccept      = "dtag_transfer_accept"
-	EventTypeDTagTransferRefuse      = "dtag_transfer_refuse"
-	EventTypeDTagTransferCancel      = "dtag_transfer_cancel"
+	EventTypeProfileSaved            = "save_profile"
+	EventTypeProfileDeleted          = "delete_profile"
+	EventTypeDTagTransferRequest     = "create_dtag_transfer_request"
+	EventTypeDTagTransferAccept      = "accept_dtag_transfer_request"
+	EventTypeDTagTransferRefuse      = "refuse_dtag_transfer_request"
+	EventTypeDTagTransferCancel      = "cancel_dtag_transfer_request"
 	EventTypeLinkChainAccount        = "link_chain_account"
 	EventTypeUnlinkChainAccount      = "unlink_chain_account"
 	EventTypeLinkChainAccountPacket  = "link_chain_account_packet"
-	EventTypePacket                  = "profiles_verification_packet"
+	EventTypePacket                  = "receive_profiles_verification_packet"
 	EventTypeTimeout                 = "timeout"
-	EventTypesApplicationLinkCreated = "application_link_created"
+	EventTypesApplicationLinkCreated = "link_application"
+	EventTypeApplicationLinkDeleted  = "unlink_application"
 	EventTypesApplicationLinkSaved   = "application_link_saved"
-	EventTypeApplicationLinkDeleted  = "application_link_deleted"
 
 	AttributeKeyProfileDTag                 = "profile_dtag"
 	AttributeKeyProfileCreator              = "profile_creator"
diff --git a/x/profiles/types/query.pb.go b/x/profiles/types/query.pb.go
index c5cb0c9c..dbc86efc 100644
--- a/x/profiles/types/query.pb.go
+++ b/x/profiles/types/query.pb.go
@@ -33,46 +33,46 @@ const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package
 func init() { proto.RegisterFile("desmos/profiles/v2/query.proto", fileDescriptor_fba4df0d7bde4d7c) }
 
 var fileDescriptor_fba4df0d7bde4d7c = []byte{
-	// 611 bytes of a gzipped FileDescriptorProto
-	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x94, 0x4d, 0x6b, 0x13, 0x41,
-	0x18, 0xc7, 0xb3, 0x82, 0x15, 0xe6, 0xa2, 0x0c, 0x7a, 0x48, 0x88, 0x5b, 0xac, 0xe6, 0x85, 0x34,
-	0xdd, 0x31, 0x09, 0x0a, 0x15, 0x3d, 0xd8, 0xf6, 0x52, 0x14, 0xac, 0xd2, 0x93, 0x97, 0x30, 0xbb,
-	0x99, 0x6c, 0x07, 0x37, 0x33, 0xd3, 0x9d, 0x4d, 0x34, 0x94, 0x5c, 0xbc, 0x79, 0x11, 0xc1, 0xbb,
-	0x27, 0x3f, 0x82, 0x1f, 0xc1, 0x83, 0x17, 0xb1, 0xe0, 0xc5, 0xa3, 0x24, 0x7e, 0x10, 0xc9, 0xbc,
-	0x24, 0x34, 0xcd, 0x26, 0x69, 0x6f, 0xbb, 0x3b, 0xbf, 0xff, 0x3c, 0xbf, 0x67, 0xf6, 0x61, 0x80,
-	0xdb, 0x22, 0xb2, 0xc3, 0x25, 0x12, 0x31, 0x6f, 0xd3, 0x88, 0x48, 0xd4, 0xab, 0xa3, 0xe3, 0x2e,
-	0x89, 0xfb, 0x9e, 0x88, 0x79, 0xc2, 0x21, 0xd4, 0xeb, 0x9e, 0x5d, 0xf7, 0x7a, 0xf5, 0xdc, 0xcd,
-	0x90, 0x87, 0x5c, 0x2d, 0xa3, 0xf1, 0x93, 0x26, 0x73, 0xf9, 0x90, 0xf3, 0x30, 0x22, 0x08, 0x0b,
-	0x8a, 0x30, 0x63, 0x3c, 0xc1, 0x09, 0xe5, 0x4c, 0x9a, 0xd5, 0xac, 0x59, 0x55, 0x6f, 0x7e, 0xb7,
-	0x8d, 0x30, 0x33, 0x25, 0x72, 0xc5, 0x34, 0x85, 0xa6, 0xf9, 0x62, 0xb8, 0x6a, 0x2a, 0xd7, 0x4a,
-	0x70, 0xd8, 0x8c, 0xc9, 0x71, 0x97, 0xc8, 0xc4, 0x16, 0x2c, 0xa4, 0xef, 0x8a, 0x63, 0xdc, 0xb1,
-	0x58, 0x25, 0x15, 0x0b, 0x8e, 0x30, 0x65, 0xcd, 0x88, 0xb2, 0x37, 0x96, 0x2d, 0xa7, 0xb2, 0x58,
-	0x88, 0x33, 0x64, 0x36, 0xe0, 0x63, 0xb2, 0xa9, 0x0f, 0x49, 0xbf, 0xd8, 0x82, 0xfa, 0x0d, 0xf9,
-	0x58, 0x12, 0x9d, 0x46, 0xbd, 0x9a, 0x4f, 0x12, 0x5c, 0x43, 0x02, 0x87, 0x94, 0xa9, 0x53, 0xd3,
-	0x6c, 0xfd, 0x3b, 0x00, 0x57, 0x5f, 0x8e, 0x11, 0xf8, 0xc1, 0x01, 0xd7, 0x0e, 0x74, 0x59, 0x58,
-	0xf2, 0xce, 0xff, 0x13, 0x4f, 0x61, 0x86, 0x78, 0xa5, 0x4f, 0x22, 0x57, 0x5e, 0x0e, 0x4a, 0xc1,
-	0x99, 0x24, 0x1b, 0x9b, 0xef, 0x7f, 0xff, 0xfb, 0x7c, 0xa5, 0x00, 0xef, 0xa2, 0x39, 0x2d, 0x4e,
-	0x9e, 0x4f, 0xba, 0x92, 0xc4, 0x03, 0xf8, 0xcb, 0x01, 0xf9, 0x7d, 0x16, 0xf0, 0x0e, 0x65, 0xe1,
-	0xde, 0x21, 0x0e, 0x0f, 0x63, 0xcc, 0x64, 0x9b, 0xc4, 0xa6, 0xac, 0x84, 0x8f, 0x53, 0xeb, 0x2e,
-	0x8a, 0x59, 0xeb, 0x27, 0x97, 0x4c, 0x9b, 0x56, 0xea, 0xaa, 0x95, 0x2a, 0xac, 0xcc, 0x6b, 0x45,
-	0x0d, 0x4a, 0x62, 0xa2, 0x93, 0x89, 0x81, 0x1f, 0x1d, 0x00, 0x76, 0xc7, 0xbf, 0xfb, 0xf9, 0xf8,
-	0x1f, 0xc2, 0x4a, 0xaa, 0xc1, 0x14, 0xb2, 0xb6, 0x9b, 0x2b, 0xb1, 0xc6, 0xad, 0xa4, 0xdc, 0xee,
-	0xc0, 0xf5, 0x79, 0x6e, 0x6a, 0xde, 0xb6, 0xd4, 0x14, 0xc1, 0xaf, 0x0e, 0xb8, 0x3e, 0xc9, 0xbf,
-	0x78, 0xcb, 0x48, 0x2c, 0x21, 0x5a, 0x5e, 0x49, 0x93, 0x56, 0xed, 0xfe, 0xea, 0x01, 0xe3, 0xe7,
-	0x29, 0xbf, 0x32, 0x2c, 0x2e, 0xf1, 0x43, 0x5c, 0x2b, 0x7d, 0x71, 0xc0, 0x8d, 0xa7, 0x42, 0x44,
-	0x34, 0x50, 0x53, 0xab, 0x4f, 0x2f, 0xbd, 0xec, 0x2c, 0x6a, 0x45, 0x6b, 0x17, 0x48, 0x18, 0xd3,
-	0x82, 0x32, 0x5d, 0x87, 0xb7, 0xe7, 0x99, 0x62, 0x21, 0xcc, 0x39, 0xfe, 0x74, 0x40, 0x76, 0x66,
-	0x8f, 0x9d, 0xfe, 0x6e, 0x44, 0x09, 0x4b, 0xf6, 0xf7, 0xe0, 0xf6, 0xaa, 0x75, 0xa7, 0x19, 0xab,
-	0xfc, 0xe8, 0x32, 0x51, 0xe3, 0xbe, 0xad, 0xdc, 0x1b, 0xb0, 0xb6, 0xd0, 0x1d, 0x05, 0x2a, 0x27,
-	0xd1, 0x89, 0x7e, 0x68, 0xd2, 0xd6, 0x00, 0x7e, 0x73, 0xc0, 0xad, 0x99, 0x02, 0x66, 0x3a, 0x1e,
-	0xac, 0x2a, 0x74, 0x76, 0x46, 0x1e, 0x5e, 0x34, 0x66, 0x7a, 0xa8, 0xaa, 0x1e, 0x8a, 0xf0, 0xde,
-	0xe2, 0x1e, 0xcc, 0x9c, 0x0c, 0xc0, 0xda, 0x81, 0xba, 0x74, 0x61, 0x31, 0xfd, 0x4a, 0x52, 0x80,
-	0xf5, 0x2a, 0x2d, 0xe5, 0x8c, 0xc8, 0x86, 0x12, 0xc9, 0xc3, 0xdc, 0xdc, 0x9b, 0x4b, 0xb1, 0x3b,
-	0xcf, 0x7e, 0x0c, 0x5d, 0xe7, 0x74, 0xe8, 0x3a, 0x7f, 0x87, 0xae, 0xf3, 0x69, 0xe4, 0x66, 0x4e,
-	0x47, 0x6e, 0xe6, 0xcf, 0xc8, 0xcd, 0xbc, 0xae, 0x85, 0x34, 0x39, 0xea, 0xfa, 0x5e, 0xc0, 0x3b,
-	0x26, 0xbf, 0x15, 0x61, 0x5f, 0xda, 0xbd, 0x7a, 0x0d, 0xf4, 0x6e, 0xba, 0x61, 0xd2, 0x17, 0x44,
-	0xfa, 0x6b, 0xea, 0x6a, 0x6e, 0xfc, 0x0f, 0x00, 0x00, 0xff, 0xff, 0x2e, 0xcf, 0xbd, 0x67, 0x39,
-	0x07, 0x00, 0x00,
+	// 614 bytes of a gzipped FileDescriptorProto
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x94, 0x4f, 0x6b, 0x13, 0x4f,
+	0x18, 0xc7, 0xbb, 0x3f, 0xf8, 0x55, 0x98, 0x8b, 0x32, 0xe8, 0x21, 0x21, 0x6e, 0xb1, 0x9a, 0x3f,
+	0xa4, 0xc9, 0x8e, 0x49, 0x50, 0xa8, 0xe8, 0xc1, 0xb6, 0x97, 0xa2, 0x60, 0x95, 0x9e, 0xbc, 0x84,
+	0xd9, 0xcd, 0x64, 0x3b, 0xb8, 0x99, 0x99, 0xee, 0x6c, 0xa2, 0xa1, 0xe4, 0xe2, 0xcd, 0x8b, 0x08,
+	0xde, 0x3d, 0xf9, 0x12, 0x7c, 0x09, 0x1e, 0xbc, 0x88, 0x05, 0x2f, 0x1e, 0x25, 0xf1, 0x85, 0xc8,
+	0xce, 0x9f, 0x86, 0xc6, 0x6c, 0x92, 0xf6, 0xb6, 0xbb, 0xf3, 0xf9, 0xce, 0xf3, 0x79, 0x66, 0x1f,
+	0x06, 0xb8, 0x1d, 0x22, 0x7b, 0x5c, 0x22, 0x11, 0xf3, 0x2e, 0x8d, 0x88, 0x44, 0x83, 0x26, 0x3a,
+	0xee, 0x93, 0x78, 0xe8, 0x89, 0x98, 0x27, 0x1c, 0x42, 0xbd, 0xee, 0xd9, 0x75, 0x6f, 0xd0, 0xcc,
+	0x5f, 0x0f, 0x79, 0xc8, 0xd5, 0x32, 0x4a, 0x9f, 0x34, 0x99, 0x2f, 0x84, 0x9c, 0x87, 0x11, 0x41,
+	0x58, 0x50, 0x84, 0x19, 0xe3, 0x09, 0x4e, 0x28, 0x67, 0xd2, 0xac, 0xe6, 0xcc, 0xaa, 0x7a, 0xf3,
+	0xfb, 0x5d, 0x84, 0x99, 0x29, 0x91, 0x2f, 0x65, 0x29, 0xb4, 0xcd, 0x17, 0xc3, 0xd5, 0x32, 0xb9,
+	0x4e, 0x82, 0xc3, 0x76, 0x4c, 0x8e, 0xfb, 0x44, 0x26, 0xb6, 0x60, 0x31, 0x7b, 0x57, 0x1c, 0xe3,
+	0x9e, 0xc5, 0xaa, 0x99, 0x58, 0x70, 0x84, 0x29, 0x6b, 0x47, 0x94, 0xbd, 0xb2, 0x6c, 0x25, 0x93,
+	0xc5, 0x42, 0x9c, 0x23, 0x73, 0x01, 0x4f, 0xc9, 0xb6, 0x3e, 0x24, 0xfd, 0x62, 0x0b, 0xea, 0x37,
+	0xe4, 0x63, 0x49, 0x74, 0x1a, 0x0d, 0x1a, 0x3e, 0x49, 0x70, 0x03, 0x09, 0x1c, 0x52, 0xa6, 0x4e,
+	0x4d, 0xb3, 0xcd, 0xaf, 0x00, 0xfc, 0xff, 0x3c, 0x45, 0xe0, 0x3b, 0x07, 0x5c, 0x39, 0xd0, 0x65,
+	0x61, 0xd9, 0xfb, 0xf7, 0x9f, 0x78, 0x0a, 0x33, 0xc4, 0x0b, 0x7d, 0x12, 0xf9, 0xca, 0x72, 0x50,
+	0x0a, 0xce, 0x24, 0xd9, 0xdc, 0x7a, 0xfb, 0xf3, 0xcf, 0xc7, 0xff, 0x8a, 0xf0, 0x36, 0x9a, 0xd3,
+	0xe2, 0xd9, 0xf3, 0x49, 0x5f, 0x92, 0x78, 0x04, 0x7f, 0x38, 0xa0, 0xb0, 0xcf, 0x02, 0xde, 0xa3,
+	0x2c, 0xdc, 0x3b, 0xc4, 0xe1, 0x61, 0x8c, 0x99, 0xec, 0x92, 0xd8, 0x94, 0x95, 0xf0, 0x61, 0x66,
+	0xdd, 0x45, 0x31, 0x6b, 0xfd, 0xe8, 0x92, 0x69, 0xd3, 0x4a, 0x53, 0xb5, 0x52, 0x83, 0xd5, 0x79,
+	0xad, 0xa4, 0x83, 0x52, 0x4f, 0x4c, 0xb4, 0x6e, 0x27, 0x06, 0xbe, 0x77, 0x00, 0xd8, 0x4d, 0x7f,
+	0xf7, 0xd3, 0xf4, 0x1f, 0xc2, 0x6a, 0xa6, 0xc1, 0x14, 0xb2, 0xb6, 0x5b, 0x2b, 0xb1, 0xc6, 0xad,
+	0xac, 0xdc, 0x6e, 0xc1, 0x8d, 0x79, 0x6e, 0x6a, 0xde, 0xea, 0x6a, 0x8a, 0xe0, 0x67, 0x07, 0x5c,
+	0x3d, 0xcb, 0x3f, 0x7b, 0xcd, 0x48, 0x2c, 0x21, 0x5a, 0x5e, 0x49, 0x93, 0x56, 0xed, 0xee, 0xea,
+	0x01, 0xe3, 0xe7, 0x29, 0xbf, 0x0a, 0x2c, 0x2d, 0xf1, 0x43, 0x5c, 0x2b, 0x7d, 0x72, 0xc0, 0xb5,
+	0xc7, 0x42, 0x44, 0x34, 0x50, 0x53, 0xab, 0x4f, 0x2f, 0xbb, 0xec, 0x2c, 0x6a, 0x45, 0x1b, 0x17,
+	0x48, 0x18, 0xd3, 0xa2, 0x32, 0xdd, 0x80, 0x37, 0xe7, 0x99, 0x62, 0x21, 0xcc, 0x39, 0x7e, 0x77,
+	0x40, 0x6e, 0x66, 0x8f, 0x9d, 0xe1, 0x6e, 0x44, 0x09, 0x4b, 0xf6, 0xf7, 0xe0, 0xf6, 0xaa, 0x75,
+	0xa7, 0x19, 0xab, 0xfc, 0xe0, 0x32, 0x51, 0xe3, 0xbe, 0xad, 0xdc, 0x5b, 0xb0, 0xb1, 0xd0, 0x1d,
+	0x05, 0x2a, 0x27, 0xd1, 0x89, 0x7e, 0x68, 0xd3, 0xce, 0x08, 0x7e, 0x71, 0xc0, 0x8d, 0x99, 0x02,
+	0x66, 0x3a, 0xee, 0xad, 0x2a, 0x74, 0x7e, 0x46, 0xee, 0x5f, 0x34, 0x66, 0x7a, 0xa8, 0xa9, 0x1e,
+	0x4a, 0xf0, 0xce, 0xe2, 0x1e, 0xcc, 0x9c, 0x8c, 0xc0, 0xfa, 0x81, 0xba, 0x74, 0x61, 0x29, 0xfb,
+	0x4a, 0x52, 0x80, 0xf5, 0x2a, 0x2f, 0xe5, 0x8c, 0xc8, 0xa6, 0x12, 0x29, 0xc0, 0xfc, 0xdc, 0x9b,
+	0x4b, 0xb1, 0x3b, 0x4f, 0xbe, 0x8d, 0x5d, 0xe7, 0x74, 0xec, 0x3a, 0xbf, 0xc7, 0xae, 0xf3, 0x61,
+	0xe2, 0xae, 0x9d, 0x4e, 0xdc, 0xb5, 0x5f, 0x13, 0x77, 0xed, 0x65, 0x23, 0xa4, 0xc9, 0x51, 0xdf,
+	0xf7, 0x02, 0xde, 0x33, 0xf9, 0x7a, 0x84, 0x7d, 0x69, 0xf7, 0x1a, 0xb4, 0xd0, 0x9b, 0xe9, 0x86,
+	0xc9, 0x50, 0x10, 0xe9, 0xaf, 0xab, 0xab, 0xb9, 0xf5, 0x37, 0x00, 0x00, 0xff, 0xff, 0xe6, 0x22,
+	0xf5, 0xbf, 0x39, 0x07, 0x00, 0x00,
 }
 
 // Reference imports to suppress errors if they are not otherwise used.
diff --git a/x/profiles/types/query.pb.gw.go b/x/profiles/types/query.pb.gw.go
index 6acc9045..5ec0613d 100644
--- a/x/profiles/types/query.pb.gw.go
+++ b/x/profiles/types/query.pb.gw.go
@@ -710,7 +710,7 @@ func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie
 var (
 	pattern_Query_Profile_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 1, 1, 0, 4, 1, 5, 3}, []string{"desmos", "profiles", "v2", "user"}, "", runtime.AssumeColonVerbOpt(true)))
 
-	pattern_Query_IncomingDTagTransferRequests_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"desmos", "profiles", "v2", "dtag_transfer_requests"}, "", runtime.AssumeColonVerbOpt(true)))
+	pattern_Query_IncomingDTagTransferRequests_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"desmos", "profiles", "v2", "dtag-transfer-requests"}, "", runtime.AssumeColonVerbOpt(true)))
 
 	pattern_Query_ChainLinks_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"desmos", "profiles", "v2", "chain-links"}, "", runtime.AssumeColonVerbOpt(true)))
 
diff --git a/x/relationships/keeper/migrations.go b/x/relationships/keeper/migrations.go
index 1b406fd3..642422cd 100644
--- a/x/relationships/keeper/migrations.go
+++ b/x/relationships/keeper/migrations.go
@@ -3,6 +3,8 @@ package keeper
 import (
 	sdk "github.com/cosmos/cosmos-sdk/types"
 
+	v2 "github.com/desmos-labs/desmos/v3/x/relationships/legacy/v2"
+
 	profilesv4 "github.com/desmos-labs/desmos/v3/x/profiles/legacy/v4"
 
 	v1 "github.com/desmos-labs/desmos/v3/x/relationships/legacy/v1"
@@ -28,3 +30,8 @@ func NewMigrator(keeper Keeper, pk profilesv4.Keeper) Migrator {
 func (m Migrator) Migrate1To2(ctx sdk.Context) error {
 	return v1.MigrateStore(ctx, m.pk, m.keeper.storeKey, m.keeper.cdc)
 }
+
+// Migrate1To2 migrates from version 2 to 3.
+func (m Migrator) Migrate2To3(ctx sdk.Context) error {
+	return v2.MigrateStore(ctx, m.keeper.storeKey, m.keeper.cdc)
+}
diff --git a/x/relationships/keeper/msg_server.go b/x/relationships/keeper/msg_server.go
index 3be3921c..faa4c055 100644
--- a/x/relationships/keeper/msg_server.go
+++ b/x/relationships/keeper/msg_server.go
@@ -49,6 +49,7 @@ func (k msgServer) CreateRelationship(goCtx context.Context, msg *types.MsgCreat
 		sdk.NewEvent(
 			sdk.EventTypeMessage,
 			sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory),
+			sdk.NewAttribute(sdk.AttributeKeyAction, sdk.MsgTypeURL(msg)),
 			sdk.NewAttribute(sdk.AttributeKeySender, msg.Signer),
 		),
 		sdk.NewEvent(
@@ -83,10 +84,11 @@ func (k msgServer) DeleteRelationship(goCtx context.Context, msg *types.MsgDelet
 		sdk.NewEvent(
 			sdk.EventTypeMessage,
 			sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory),
+			sdk.NewAttribute(sdk.AttributeKeyAction, sdk.MsgTypeURL(msg)),
 			sdk.NewAttribute(sdk.AttributeKeySender, msg.Signer),
 		),
 		sdk.NewEvent(
-			types.EventTypeRelationshipsDeleted,
+			types.EventTypeRelationshipDeleted,
 			sdk.NewAttribute(types.AttributeRelationshipCreator, msg.Signer),
 			sdk.NewAttribute(types.AttributeRelationshipCounterparty, msg.Counterparty),
 			sdk.NewAttribute(types.AttributeKeySubspace, fmt.Sprintf("%d", msg.SubspaceID)),
@@ -117,6 +119,7 @@ func (k msgServer) BlockUser(goCtx context.Context, msg *types.MsgBlockUser) (*t
 		sdk.NewEvent(
 			sdk.EventTypeMessage,
 			sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory),
+			sdk.NewAttribute(sdk.AttributeKeyAction, sdk.MsgTypeURL(msg)),
 			sdk.NewAttribute(sdk.AttributeKeySender, msg.Blocker),
 		),
 		sdk.NewEvent(
@@ -151,6 +154,7 @@ func (k msgServer) UnblockUser(goCtx context.Context, msg *types.MsgUnblockUser)
 		sdk.NewEvent(
 			sdk.EventTypeMessage,
 			sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory),
+			sdk.NewAttribute(sdk.AttributeKeyAction, sdk.MsgTypeURL(msg)),
 			sdk.NewAttribute(sdk.AttributeKeySender, msg.Blocker),
 		),
 		sdk.NewEvent(
diff --git a/x/relationships/legacy/v1/keys.go b/x/relationships/legacy/v1/keys.go
new file mode 100644
index 00000000..7c3f2e17
--- /dev/null
+++ b/x/relationships/legacy/v1/keys.go
@@ -0,0 +1,45 @@
+package v1
+
+// DONTCOVER
+
+import (
+	subspacestypes "github.com/desmos-labs/desmos/v3/x/subspaces/types"
+)
+
+var (
+	RelationshipsStorePrefix = []byte("relationships")
+	UsersBlocksStorePrefix   = []byte("users_blocks")
+)
+
+// SubspaceRelationshipsPrefix returns the prefix used to store all relationships for the given subspace
+func SubspaceRelationshipsPrefix(subspaceID uint64) []byte {
+	return append(RelationshipsStorePrefix, subspacestypes.GetSubspaceIDBytes(subspaceID)...)
+}
+
+// UserRelationshipsSubspacePrefix returns the prefix used to store all the relationships created by the user
+// with the given address for the subspace having the given id
+func UserRelationshipsSubspacePrefix(subspace uint64, user string) []byte {
+	return append(SubspaceRelationshipsPrefix(subspace), []byte(user)...)
+}
+
+// RelationshipsStoreKey returns the store key used to store the relationships containing the given data
+func RelationshipsStoreKey(user, counterparty string, subspace uint64) []byte {
+	return append(UserRelationshipsSubspacePrefix(subspace, user), []byte(counterparty)...)
+}
+
+// SubspaceBlocksPrefix returns the store prefix used to store the blocks for the given subspace
+func SubspaceBlocksPrefix(subspaceID uint64) []byte {
+	return append(UsersBlocksStorePrefix, subspacestypes.GetSubspaceIDBytes(subspaceID)...)
+}
+
+// BlockerSubspacePrefix returns the store prefix used to store the blocks that the given blocker
+// has created inside the specified subspace
+func BlockerSubspacePrefix(subspaceID uint64, blocker string) []byte {
+	return append(SubspaceBlocksPrefix(subspaceID), []byte(blocker)...)
+}
+
+// UserBlockStoreKey returns the store key used to save the block made by the given blocker,
+// inside the specified subspace and towards the given blocked user
+func UserBlockStoreKey(blocker, blockedUser string, subspace uint64) []byte {
+	return append(BlockerSubspacePrefix(subspace, blocker), []byte(blockedUser)...)
+}
diff --git a/x/relationships/legacy/v2/store.go b/x/relationships/legacy/v2/store.go
new file mode 100644
index 00000000..16117ea2
--- /dev/null
+++ b/x/relationships/legacy/v2/store.go
@@ -0,0 +1,103 @@
+package v2
+
+import (
+	"github.com/cosmos/cosmos-sdk/codec"
+	"github.com/cosmos/cosmos-sdk/store/prefix"
+	sdk "github.com/cosmos/cosmos-sdk/types"
+
+	v1 "github.com/desmos-labs/desmos/v3/x/relationships/legacy/v1"
+	"github.com/desmos-labs/desmos/v3/x/relationships/types"
+)
+
+// MigrateStore performs in-place store migrations from v1 to v2.
+// The migration includes:
+//
+// - migrate all relationships keys to the new ones
+// - migrate all user blocks keys to the new ones
+func MigrateStore(ctx sdk.Context, storeKey sdk.StoreKey, cdc codec.BinaryCodec) error {
+	store := ctx.KVStore(storeKey)
+
+	err := migrateRelationships(store, cdc)
+	if err != nil {
+		return err
+	}
+
+	err = migrateUserBlocks(store, cdc)
+	if err != nil {
+		return err
+	}
+
+	return nil
+}
+
+// migrateRelationships migrates all the relationships from using the old key to using the new key
+func migrateRelationships(store sdk.KVStore, cdc codec.BinaryCodec) error {
+	prefixStore := prefix.NewStore(store, v1.RelationshipsStorePrefix)
+	iterator := prefixStore.Iterator(nil, nil)
+
+	// Read all the existing relationships and the associated keys
+	var keys [][]byte
+	var relationships []types.Relationship
+	for ; iterator.Valid(); iterator.Next() {
+		keys = append(keys, append(v1.RelationshipsStorePrefix, iterator.Key()...))
+
+		var relationship types.Relationship
+		err := cdc.Unmarshal(iterator.Value(), &relationship)
+		if err != nil {
+			return err
+		}
+		relationships = append(relationships, relationship)
+	}
+	iterator.Close()
+
+	for i, relationship := range relationships {
+		// Delete the old key
+		store.Delete(keys[i])
+
+		bz, err := cdc.Marshal(&relationships[i])
+		if err != nil {
+			return err
+		}
+
+		// Store the relationship with the new key
+		store.Set(types.RelationshipsStoreKey(relationship.Creator, relationship.Counterparty, relationship.SubspaceID), bz)
+	}
+
+	return nil
+}
+
+// migrateUserBlocks migrates all the user blocks from using the old key to using the new key
+func migrateUserBlocks(store sdk.KVStore, cdc codec.BinaryCodec) error {
+	prefixStore := prefix.NewStore(store, v1.UsersBlocksStorePrefix)
+	iterator := prefixStore.Iterator(nil, nil)
+
+	// Read all the existing blocks and the associated keys
+	var keys [][]byte
+	var blocks []types.UserBlock
+	for ; iterator.Valid(); iterator.Next() {
+		keys = append(keys, append(v1.UsersBlocksStorePrefix, iterator.Key()...))
+
+		var block types.UserBlock
+		err := cdc.Unmarshal(iterator.Value(), &block)
+		if err != nil {
+			return err
+		}
+		blocks = append(blocks, block)
+	}
+	iterator.Close()
+
+	for i, block := range blocks {
+		// Delete the old key
+		store.Delete(keys[i])
+
+		bz, err := cdc.Marshal(&blocks[i])
+		if err != nil {
+			return err
+		}
+
+		// Store the block with the new key
+		store.Set(types.UserBlockStoreKey(block.Blocker, block.Blocked, block.SubspaceID), bz)
+	}
+
+	return nil
+}
diff --git a/x/relationships/module.go b/x/relationships/module.go
index 7641ca8a..37db0891 100644
--- a/x/relationships/module.go
+++ b/x/relationships/module.go
@@ -33,7 +33,7 @@ import (
 )
 
 const (
-	consensusVersion = 2
+	consensusVersion = 3
 )
 
 // type check to ensure the interface is properly implemented
@@ -118,6 +118,10 @@ func (am AppModule) RegisterServices(cfg module.Configurator) {
 	if err != nil {
 		panic(err)
 	}
+	err = cfg.RegisterMigration(types.ModuleName, 2, m.Migrate2To3)
+	if err != nil {
+		panic(err)
+	}
 }
 
 // NewAppModule creates a new AppModule Object
diff --git a/x/relationships/types/events.go b/x/relationships/types/events.go
index d697196e..96dc0889 100644
--- a/x/relationships/types/events.go
+++ b/x/relationships/types/events.go
@@ -3,10 +3,10 @@ package types
 // DONTCOVER
 
 const (
-	EventTypeRelationshipCreated  = "relationship_created"
-	EventTypeRelationshipsDeleted = "relationships_deleted"
-	EventTypeBlockUser            = "block_user"
-	EventTypeUnblockUser          = "unblock_user"
+	EventTypeRelationshipCreated = "create_relationship"
+	EventTypeRelationshipDeleted = "delete_relationship"
+	EventTypeBlockUser           = "block_user"
+	EventTypeUnblockUser         = "unblock_user"
 
 	AttributeValueCategory            = ModuleName
 	AttributeRelationshipCreator      = "creator"
diff --git a/x/relationships/types/keys.go b/x/relationships/types/keys.go
index 61db1bc0..b7ce62c9 100644
--- a/x/relationships/types/keys.go
+++ b/x/relationships/types/keys.go
@@ -18,8 +18,8 @@ const (
 )
 
 var (
-	RelationshipsStorePrefix = []byte("relationships")
-	UsersBlocksStorePrefix   = []byte("users_blocks")
+	RelationshipsStorePrefix = []byte{0x01}
+	UsersBlocksStorePrefix   = []byte{0x02}
 )
 
 // SubspaceRelationshipsPrefix returns the prefix used to store all relationships for the given subspace
diff --git a/x/subspaces/keeper/msg_server.go b/x/subspaces/keeper/msg_server.go
index f22224dc..6b88584a 100644
--- a/x/subspaces/keeper/msg_server.go
+++ b/x/subspaces/keeper/msg_server.go
@@ -49,6 +49,7 @@ func (k msgServer) CreateSubspace(goCtx context.Context, msg *types.MsgCreateSub
 		sdk.NewEvent(
 			sdk.EventTypeMessage,
 			sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory),
+			sdk.NewAttribute(sdk.AttributeKeyAction, sdk.MsgTypeURL(msg)),
 			sdk.NewAttribute(sdk.AttributeKeySender, subspace.Creator),
 		),
 		sdk.NewEvent(
@@ -99,6 +100,7 @@ func (k msgServer) EditSubspace(goCtx context.Context, msg *types.MsgEditSubspac
 		sdk.NewEvent(
 			sdk.EventTypeMessage,
 			sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory),
+			sdk.NewAttribute(sdk.AttributeKeyAction, sdk.MsgTypeURL(msg)),
 			sdk.NewAttribute(sdk.AttributeKeySender, msg.Signer),
 		),
 		sdk.NewEvent(
@@ -136,6 +138,7 @@ func (k msgServer) DeleteSubspace(goCtx context.Context, msg *types.MsgDeleteSub
 		sdk.NewEvent(
 			sdk.EventTypeMessage,
 			sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory),
+			sdk.NewAttribute(sdk.AttributeKeyAction, sdk.MsgTypeURL(msg)),
 			sdk.NewAttribute(sdk.AttributeKeySender, msg.Signer),
 		),
 		sdk.NewEvent(
@@ -196,6 +199,7 @@ func (k msgServer) CreateUserGroup(goCtx context.Context, msg *types.MsgCreateUs
 		sdk.NewEvent(
 			sdk.EventTypeMessage,
 			sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory),
+			sdk.NewAttribute(sdk.AttributeKeyAction, sdk.MsgTypeURL(msg)),
 			sdk.NewAttribute(sdk.AttributeKeySender, msg.Creator),
 		),
 		sdk.NewEvent(
@@ -247,6 +251,7 @@ func (k msgServer) EditUserGroup(goCtx context.Context, msg *types.MsgEditUserGr
 		sdk.NewEvent(
 			sdk.EventTypeMessage,
 			sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory),
+			sdk.NewAttribute(sdk.AttributeKeyAction, sdk.MsgTypeURL(msg)),
 			sdk.NewAttribute(sdk.AttributeKeySender, msg.Signer),
 		),
 		sdk.NewEvent(
@@ -303,6 +308,7 @@ func (k msgServer) SetUserGroupPermissions(goCtx context.Context, msg *types.Msg
 		sdk.NewEvent(
 			sdk.EventTypeMessage,
 			sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory),
+			sdk.NewAttribute(sdk.AttributeKeyAction, sdk.MsgTypeURL(msg)),
 			sdk.NewAttribute(sdk.AttributeKeySender, signer.String()),
 		),
 		sdk.NewEvent(
@@ -346,6 +352,7 @@ func (k msgServer) DeleteUserGroup(goCtx context.Context, msg *types.MsgDeleteUs
 		sdk.NewEvent(
 			sdk.EventTypeMessage,
 			sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory),
+			sdk.NewAttribute(sdk.AttributeKeyAction, sdk.MsgTypeURL(msg)),
 			sdk.NewAttribute(sdk.AttributeKeySender, msg.Signer),
 		),
 		sdk.NewEvent(
@@ -402,6 +409,7 @@ func (k msgServer) AddUserToUserGroup(goCtx context.Context, msg *types.MsgAddUs
 		sdk.NewEvent(
 			sdk.EventTypeMessage,
 			sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory),
+			sdk.NewAttribute(sdk.AttributeKeyAction, sdk.MsgTypeURL(msg)),
 			sdk.NewAttribute(sdk.AttributeKeySender, msg.Signer),
 		),
 		sdk.NewEvent(
@@ -456,6 +464,7 @@ func (k msgServer) RemoveUserFromUserGroup(goCtx context.Context, msg *types.Msg
 		sdk.NewEvent(
 			sdk.EventTypeMessage,
 			sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory),
+			sdk.NewAttribute(sdk.AttributeKeyAction, sdk.MsgTypeURL(msg)),
 			sdk.NewAttribute(sdk.AttributeKeySender, msg.Signer),
 		),
 		sdk.NewEvent(
@@ -510,6 +519,7 @@ func (k msgServer) SetUserPermissions(goCtx context.Context, msg *types.MsgSetUs
 		sdk.NewEvent(
 			sdk.EventTypeMessage,
 			sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory),
+			sdk.NewAttribute(sdk.AttributeKeyAction, sdk.MsgTypeURL(msg)),
 			sdk.NewAttribute(sdk.AttributeKeySender, signer.String()),
 		),
 		sdk.NewEvent(
diff --git a/x/supply/types/query.pb.go b/x/supply/types/query.pb.go
index 179d7cd5..533ec8f7 100644
--- a/x/supply/types/query.pb.go
+++ b/x/supply/types/query.pb.go
@@ -38,7 +38,8 @@ const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package
 type QueryTotalSupplyRequest struct {
 	// coin denom to query the circulating supply for
 	Denom string `protobuf:"bytes,1,opt,name=denom,proto3" json:"denom,omitempty"`
-	// divider_exponent is a factor used to power the divider used to convert the supply to the desired representation
+	// divider_exponent is a factor used to power the divider used to convert the
+	// supply to the desired representation
 	DividerExponent uint64 `protobuf:"varint,2,opt,name=divider_exponent,json=dividerExponent,proto3" json:"divider_exponent,omitempty"`
 }
 
@@ -75,7 +76,8 @@ func (m *QueryTotalSupplyRequest) XXX_DiscardUnknown() {
 
 var xxx_messageInfo_QueryTotalSupplyRequest proto.InternalMessageInfo
 
-// QueryTotalSupplyResponse is the response type for the Query/TotalSupply RPC method
+// QueryTotalSupplyResponse is the response type for the Query/TotalSupply RPC
+// method
 type QueryTotalSupplyResponse struct {
 	TotalSupply github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,1,opt,name=total_supply,json=totalSupply,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"total_supply"`
 }
@@ -113,11 +115,13 @@ func (m *QueryTotalSupplyResponse) XXX_DiscardUnknown() {
 
 var xxx_messageInfo_QueryTotalSupplyResponse proto.InternalMessageInfo
 
-// QueryCirculatingSupplyRequest is the request type for the Query/CirculatingSupply RPC method
+// QueryCirculatingSupplyRequest is the request type for the
+// Query/CirculatingSupply RPC method
 type QueryCirculatingSupplyRequest struct {
 	// coin denom to query the circulating supply for
 	Denom string `protobuf:"bytes,1,opt,name=denom,proto3" json:"denom,omitempty"`
-	// divider_exponent is a factor used to power the divider used to convert the supply to the desired representation
+	// divider_exponent is a factor used to power the divider used to convert the
+	// supply to the desired representation
 	DividerExponent uint64 `protobuf:"varint,2,opt,name=divider_exponent,json=dividerExponent,proto3" json:"divider_exponent,omitempty"`
 }
 
@@ -154,7 +158,8 @@ func (m *QueryCirculatingSupplyRequest) XXX_DiscardUnknown() {
 
 var xxx_messageInfo_QueryCirculatingSupplyRequest proto.InternalMessageInfo
 
-// QueryCirculatingSupplyRequest is the response type for the Query/CirculatingSupply RPC method
+// QueryCirculatingSupplyRequest is the response type for the
+// Query/CirculatingSupply RPC method
 type QueryCirculatingSupplyResponse struct {
 	CirculatingSupply github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,1,opt,name=circulating_supply,json=circulatingSupply,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"circulating_supply"`
 }
@@ -250,7 +255,8 @@ const _ = grpc.SupportPackageIsVersion4
 type QueryClient interface {
 	// TotalSupply queries the total supply of the given denom
 	TotalSupply(ctx context.Context, in *QueryTotalSupplyRequest, opts ...grpc.CallOption) (*QueryTotalSupplyResponse, error)
-	// CirculatingSupply queries the amount of tokens circulating in the market of the given denom
+	// CirculatingSupply queries the amount of tokens circulating in the market of
+	// the given denom
 	CirculatingSupply(ctx context.Context, in *QueryCirculatingSupplyRequest, opts ...grpc.CallOption) (*QueryCirculatingSupplyResponse, error)
 }
 
@@ -284,7 +290,8 @@ func (c *queryClient) CirculatingSupply(ctx context.Context, in *QueryCirculatin
 type QueryServer interface {
 	// TotalSupply queries the total supply of the given denom
 	TotalSupply(context.Context, *QueryTotalSupplyRequest) (*QueryTotalSupplyResponse, error)
-	// CirculatingSupply queries the amount of tokens circulating in the market of the given denom
+	// CirculatingSupply queries the amount of tokens circulating in the market of
+	// the given denom
 	CirculatingSupply(context.Context, *QueryCirculatingSupplyRequest) (*QueryCirculatingSupplyResponse, error)
 }
 


Test patch:
diff --git a/x/fees/types/params_test.go b/x/fees/types/params_test.go
index d0d7e63a..ed7be503 100644
--- a/x/fees/types/params_test.go
+++ b/x/fees/types/params_test.go
@@ -18,17 +18,40 @@ func TestValidateParams(t *testing.T) {
 		shouldErr bool
 	}{
 		{
-			name: "invalid params returns error",
+			name: "invalid type returns error",
 			params: types.NewParams([]types.MinFee{
 				types.NewMinFee("", sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(1)))),
 			}),
 			shouldErr: true,
 		},
+		{
+			name: "invalid amount returns error",
+			params: types.NewParams([]types.MinFee{
+				types.NewMinFee("/desmos.profiles.v2.SaveProfile", sdk.Coins{sdk.Coin{Denom: "", Amount: sdk.NewInt(1)}}),
+			}),
+			shouldErr: true,
+		},
+		{
+			name: "duplicated min fee returns error",
+			params: types.NewParams([]types.MinFee{
+				types.NewMinFee("/desmos.profiles.v2.SaveProfile", sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(1)))),
+				types.NewMinFee("/desmos.profiles.v2.SaveProfile", sdk.NewCoins(sdk.NewCoin("photino", sdk.NewInt(1)))),
+			}),
+			shouldErr: true,
+		},
 		{
 			name:      "default params returns no error",
 			params:    types.DefaultParams(),
 			shouldErr: false,
 		},
+		{
+			name: "custom params returns no error",
+			params: types.NewParams([]types.MinFee{
+				types.NewMinFee("/desmos.profiles.v2.SaveProfile", sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(1)))),
+				types.NewMinFee("/desmos.profiles.v2.CreateChainLink", sdk.NewCoins(sdk.NewCoin("photino", sdk.NewInt(1)))),
+			}),
+			shouldErr: false,
+		},
 	}
 
 	for _, tc := range testCases {
diff --git a/x/profiles/client/cli/cli_app_links_test.go b/x/profiles/client/cli/cli_app_links_test.go
index 62cbbde3..29afaa51 100644
--- a/x/profiles/client/cli/cli_app_links_test.go
+++ b/x/profiles/client/cli/cli_app_links_test.go
@@ -105,6 +105,81 @@ func (s *IntegrationTestSuite) TestCmdQueryApplicationsLinks() {
 	}
 }
 
+func (s *IntegrationTestSuite) TestCmdQueryApplicationsLinkOwners() {
+	val := s.network.Validators[0]
+	testCases := []struct {
+		name           string
+		args           []string
+		shouldErr      bool
+		expectedOutput types.QueryApplicationLinkOwnersResponse
+	}{
+		{
+			name: "existing link owners are returned properly",
+			args: []string{
+				fmt.Sprintf("--%s=json", tmcli.OutputFlag),
+			},
+			shouldErr: false,
+			expectedOutput: types.QueryApplicationLinkOwnersResponse{
+				Owners: []types.QueryApplicationLinkOwnersResponse_ApplicationLinkOwnerDetails{
+					{
+						User:        "cosmos1ftkjv8njvkekk00ehwdfl5sst8zgdpenjfm4hs",
+						Application: "reddit",
+						Username:    "reddit-user",
+					},
+				},
+			},
+		},
+		{
+			name: "existing links of the given application are not found",
+			args: []string{
+				"github",
+				fmt.Sprintf("--%s=json", tmcli.OutputFlag),
+			},
+			shouldErr: false,
+			expectedOutput: types.QueryApplicationLinkOwnersResponse{
+				Owners: []types.QueryApplicationLinkOwnersResponse_ApplicationLinkOwnerDetails{},
+			},
+		},
+		{
+			name: "existing link owners of the given application are returned properly",
+			args: []string{
+				"reddit",
+				fmt.Sprintf("--%s=json", tmcli.OutputFlag),
+			},
+			shouldErr: false,
+			expectedOutput: types.QueryApplicationLinkOwnersResponse{
+				Owners: []types.QueryApplicationLinkOwnersResponse_ApplicationLinkOwnerDetails{
+					{
+						User:        "cosmos1ftkjv8njvkekk00ehwdfl5sst8zgdpenjfm4hs",
+						Application: "reddit",
+						Username:    "reddit-user",
+					},
+				},
+			},
+		},
+	}
+
+	for _, tc := range testCases {
+		tc := tc
+
+		s.Run(tc.name, func() {
+			cmd := cli.GetCmdQueryApplicationLinkOwners()
+			clientCtx := val.ClientCtx
+			out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args)
+
+			if tc.shouldErr {
+				s.Require().Error(err)
+			} else {
+				s.Require().NoError(err)
+
+				var response types.QueryApplicationLinkOwnersResponse
+				s.Require().NoError(clientCtx.JSONCodec.UnmarshalJSON(out.Bytes(), &response), out.String())
+				s.Require().Equal(tc.expectedOutput.Owners, response.Owners)
+			}
+		})
+	}
+}
+
 func (s *IntegrationTestSuite) TestCmdUnlinkApplication() {
 	val := s.network.Validators[0]
 	testCases := []struct {
diff --git a/x/profiles/client/cli/cli_chain_links_test.go b/x/profiles/client/cli/cli_chain_links_test.go
index e12a9017..5eb1e26d 100644
--- a/x/profiles/client/cli/cli_chain_links_test.go
+++ b/x/profiles/client/cli/cli_chain_links_test.go
@@ -104,6 +104,99 @@ func (s *IntegrationTestSuite) TestCmdQueryChainLinks() {
 	}
 }
 
+func (s *IntegrationTestSuite) TestCmdQueryChainLinkOwners() {
+	val := s.network.Validators[0]
+	target := s.testChainLinkAccount.GetBech32ChainLink(
+		"cosmos1ftkjv8njvkekk00ehwdfl5sst8zgdpenjfm4hs",
+		time.Date(2019, 1, 1, 00, 00, 00, 000, time.UTC),
+	).GetAddressData().GetValue()
+
+	useCases := []struct {
+		name           string
+		args           []string
+		shouldErr      bool
+		expectedOutput types.QueryChainLinkOwnersResponse
+	}{
+		{
+			name: "existing chain link owners are returned properly",
+			args: []string{
+				fmt.Sprintf("--%s=json", tmcli.OutputFlag),
+			},
+			shouldErr: false,
+			expectedOutput: types.QueryChainLinkOwnersResponse{
+				Owners: []types.QueryChainLinkOwnersResponse_ChainLinkOwnerDetails{
+					{
+						User:      "cosmos1ftkjv8njvkekk00ehwdfl5sst8zgdpenjfm4hs",
+						ChainName: "cosmos",
+						Target:    target,
+					},
+				},
+				Pagination: &query.PageResponse{
+					NextKey: nil,
+					Total:   0,
+				},
+			},
+		},
+		{
+			name: "empty array is returned properly",
+			args: []string{
+				"desmos",
+				fmt.Sprintf("--%s=json", tmcli.OutputFlag),
+			},
+			shouldErr: false,
+			expectedOutput: types.QueryChainLinkOwnersResponse{
+				Owners: []types.QueryChainLinkOwnersResponse_ChainLinkOwnerDetails{},
+				Pagination: &query.PageResponse{
+					NextKey: nil,
+					Total:   0,
+				},
+			},
+		},
+		{
+			name: "existing chain link owners of the given chain name are returned properly",
+			args: []string{
+				"cosmos",
+				fmt.Sprintf("--%s=json", tmcli.OutputFlag),
+			},
+			shouldErr: false,
+			expectedOutput: types.QueryChainLinkOwnersResponse{
+				Owners: []types.QueryChainLinkOwnersResponse_ChainLinkOwnerDetails{
+					{
+						User:      "cosmos1ftkjv8njvkekk00ehwdfl5sst8zgdpenjfm4hs",
+						ChainName: "cosmos",
+						Target:    target,
+					},
+				},
+				Pagination: &query.PageResponse{
+					NextKey: nil,
+					Total:   0,
+				},
+			},
+		},
+	}
+
+	for _, uc := range useCases {
+		uc := uc
+
+		s.Run(uc.name, func() {
+			cmd := cli.GetCmdQueryChainLinkOwners()
+			clientCtx := val.ClientCtx
+			out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, uc.args)
+
+			if uc.shouldErr {
+				s.Require().Error(err)
+			} else {
+				s.Require().NoError(err)
+
+				var response types.QueryChainLinkOwnersResponse
+				s.Require().NoError(clientCtx.JSONCodec.UnmarshalJSON(out.Bytes(), &response), out.String())
+				s.Require().Equal(uc.expectedOutput.Pagination, response.Pagination)
+				s.Require().Equal(uc.expectedOutput.Owners, response.Owners)
+			}
+		})
+	}
+}
+
 func (s *IntegrationTestSuite) TestCmdLinkChainAccount() {
 	cliCtx := s.network.Validators[0].ClientCtx
 	cliCtx.Keyring = s.keyBase
diff --git a/x/profiles/keeper/msg_server_chain_link_test.go b/x/profiles/keeper/msg_server_chain_link_test.go
index 5b8205a4..833a1f34 100644
--- a/x/profiles/keeper/msg_server_chain_link_test.go
+++ b/x/profiles/keeper/msg_server_chain_link_test.go
@@ -107,6 +107,12 @@ func (suite *KeeperTestSuite) TestMsgServer_LinkChainAccount() {
 			),
 			shouldErr: false,
 			expEvents: sdk.Events{
+				sdk.NewEvent(
+					sdk.EventTypeMessage,
+					sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory),
+					sdk.NewAttribute(sdk.AttributeKeyAction, sdk.MsgTypeURL(&types.MsgLinkChainAccount{})),
+					sdk.NewAttribute(sdk.AttributeKeySender, destAddr),
+				),
 				sdk.NewEvent(
 					types.EventTypeLinkChainAccount,
 					sdk.NewAttribute(types.AttributeKeyChainLinkSourceAddress, srcAddr),
@@ -198,6 +204,12 @@ func (suite *KeeperTestSuite) TestMsgServer_UnlinkChainAccount() {
 			),
 			shouldErr: false,
 			expEvents: sdk.Events{
+				sdk.NewEvent(
+					sdk.EventTypeMessage,
+					sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory),
+					sdk.NewAttribute(sdk.AttributeKeyAction, sdk.MsgTypeURL(&types.MsgUnlinkChainAccount{})),
+					sdk.NewAttribute(sdk.AttributeKeySender, "cosmos1y54exmx84cqtasvjnskf9f63djuuj68p7hqf47"),
+				),
 				sdk.NewEvent(
 					types.EventTypeUnlinkChainAccount,
 					sdk.NewAttribute(types.AttributeKeyChainLinkSourceAddress, "cosmos1cjf97gpzwmaf30pzvaargfgr884mpp5ak8f7ns"),
diff --git a/x/profiles/keeper/msg_server_dtag_transfers_test.go b/x/profiles/keeper/msg_server_dtag_transfers_test.go
index cde8890d..3c7d3e40 100644
--- a/x/profiles/keeper/msg_server_dtag_transfers_test.go
+++ b/x/profiles/keeper/msg_server_dtag_transfers_test.go
@@ -80,6 +80,7 @@ func (suite *KeeperTestSuite) TestMsgServer_RequestDTagTransfer() {
 				sdk.NewEvent(
 					sdk.EventTypeMessage,
 					sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory),
+					sdk.NewAttribute(sdk.AttributeKeyAction, sdk.MsgTypeURL(&types.MsgRequestDTagTransfer{})),
 					sdk.NewAttribute(sdk.AttributeKeySender, "cosmos1y54exmx84cqtasvjnskf9f63djuuj68p7hqf47"),
 				),
 				sdk.NewEvent(
@@ -148,6 +149,7 @@ func (suite *KeeperTestSuite) TestMsgServer_CancelDTagTransfer() {
 				sdk.NewEvent(
 					sdk.EventTypeMessage,
 					sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory),
+					sdk.NewAttribute(sdk.AttributeKeyAction, sdk.MsgTypeURL(&types.MsgCancelDTagTransferRequest{})),
 					sdk.NewAttribute(sdk.AttributeKeySender, "cosmos1y54exmx84cqtasvjnskf9f63djuuj68p7hqf47"),
 				),
 				sdk.NewEvent(
@@ -290,6 +292,7 @@ func (suite *KeeperTestSuite) TestMsgServer_AcceptDTagTransfer() {
 				sdk.NewEvent(
 					sdk.EventTypeMessage,
 					sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory),
+					sdk.NewAttribute(sdk.AttributeKeyAction, sdk.MsgTypeURL(&types.MsgAcceptDTagTransferRequest{})),
 					sdk.NewAttribute(sdk.AttributeKeySender, "cosmos1cjf97gpzwmaf30pzvaargfgr884mpp5ak8f7ns"),
 				),
 				sdk.NewEvent(
@@ -324,6 +327,7 @@ func (suite *KeeperTestSuite) TestMsgServer_AcceptDTagTransfer() {
 				sdk.NewEvent(
 					sdk.EventTypeMessage,
 					sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory),
+					sdk.NewAttribute(sdk.AttributeKeyAction, sdk.MsgTypeURL(&types.MsgAcceptDTagTransferRequest{})),
 					sdk.NewAttribute(sdk.AttributeKeySender, "cosmos1cjf97gpzwmaf30pzvaargfgr884mpp5ak8f7ns"),
 				),
 				sdk.NewEvent(
@@ -360,6 +364,7 @@ func (suite *KeeperTestSuite) TestMsgServer_AcceptDTagTransfer() {
 				sdk.NewEvent(
 					sdk.EventTypeMessage,
 					sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory),
+					sdk.NewAttribute(sdk.AttributeKeyAction, sdk.MsgTypeURL(&types.MsgAcceptDTagTransferRequest{})),
 					sdk.NewAttribute(sdk.AttributeKeySender, "cosmos1cjf97gpzwmaf30pzvaargfgr884mpp5ak8f7ns"),
 				),
 				sdk.NewEvent(
@@ -441,6 +446,7 @@ func (suite *KeeperTestSuite) TestMsgServer_RefuseDTagTransfer() {
 				sdk.NewEvent(
 					sdk.EventTypeMessage,
 					sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory),
+					sdk.NewAttribute(sdk.AttributeKeyAction, sdk.MsgTypeURL(&types.MsgRefuseDTagTransferRequest{})),
 					sdk.NewAttribute(sdk.AttributeKeySender, "cosmos1cjf97gpzwmaf30pzvaargfgr884mpp5ak8f7ns"),
 				),
 				sdk.NewEvent(
diff --git a/x/profiles/keeper/msgs_server_profile_test.go b/x/profiles/keeper/msgs_server_profile_test.go
index 6fbdfc89..812ccc65 100644
--- a/x/profiles/keeper/msgs_server_profile_test.go
+++ b/x/profiles/keeper/msgs_server_profile_test.go
@@ -44,6 +44,7 @@ func (suite *KeeperTestSuite) TestMsgServer_SaveProfile() {
 				sdk.NewEvent(
 					sdk.EventTypeMessage,
 					sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory),
+					sdk.NewAttribute(sdk.AttributeKeyAction, sdk.MsgTypeURL(&types.MsgSaveProfile{})),
 					sdk.NewAttribute(sdk.AttributeKeySender, "cosmos10nsdxxdvy9qka3zv0lzw8z9cnu6kanld8jh773"),
 				),
 				sdk.NewEvent(
@@ -83,6 +84,7 @@ func (suite *KeeperTestSuite) TestMsgServer_SaveProfile() {
 				sdk.NewEvent(
 					sdk.EventTypeMessage,
 					sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory),
+					sdk.NewAttribute(sdk.AttributeKeyAction, sdk.MsgTypeURL(&types.MsgSaveProfile{})),
 					sdk.NewAttribute(sdk.AttributeKeySender, "cosmos10nsdxxdvy9qka3zv0lzw8z9cnu6kanld8jh773"),
 				),
 				sdk.NewEvent(
@@ -128,6 +130,7 @@ func (suite *KeeperTestSuite) TestMsgServer_SaveProfile() {
 				sdk.NewEvent(
 					sdk.EventTypeMessage,
 					sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory),
+					sdk.NewAttribute(sdk.AttributeKeyAction, sdk.MsgTypeURL(&types.MsgSaveProfile{})),
 					sdk.NewAttribute(sdk.AttributeKeySender, "cosmos10nsdxxdvy9qka3zv0lzw8z9cnu6kanld8jh773"),
 				),
 				sdk.NewEvent(
@@ -211,6 +214,7 @@ func (suite *KeeperTestSuite) TestMsgServer_SaveProfile() {
 				sdk.NewEvent(
 					sdk.EventTypeMessage,
 					sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory),
+					sdk.NewAttribute(sdk.AttributeKeyAction, sdk.MsgTypeURL(&types.MsgSaveProfile{})),
 					sdk.NewAttribute(sdk.AttributeKeySender, "cosmos1cjf97gpzwmaf30pzvaargfgr884mpp5ak8f7ns"),
 				),
 				sdk.NewEvent(
@@ -307,6 +311,7 @@ func (suite *KeeperTestSuite) TestMsgServer_DeleteProfile() {
 				sdk.NewEvent(
 					sdk.EventTypeMessage,
 					sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory),
+					sdk.NewAttribute(sdk.AttributeKeyAction, sdk.MsgTypeURL(&types.MsgDeleteProfile{})),
 					sdk.NewAttribute(sdk.AttributeKeySender, "cosmos10nsdxxdvy9qka3zv0lzw8z9cnu6kanld8jh773"),
 				),
 				sdk.NewEvent(
diff --git a/x/relationships/keeper/msg_server_test.go b/x/relationships/keeper/msg_server_test.go
index 66aa88d2..300b969d 100644
--- a/x/relationships/keeper/msg_server_test.go
+++ b/x/relationships/keeper/msg_server_test.go
@@ -94,6 +94,7 @@ func (suite *KeeperTestSuite) TestMsgServer_CreateRelationship() {
 				sdk.NewEvent(
 					sdk.EventTypeMessage,
 					sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory),
+					sdk.NewAttribute(sdk.AttributeKeyAction, sdk.MsgTypeURL(&types.MsgCreateRelationship{})),
 					sdk.NewAttribute(sdk.AttributeKeySender, "cosmos1y54exmx84cqtasvjnskf9f63djuuj68p7hqf47"),
 				),
 				sdk.NewEvent(
@@ -205,10 +206,11 @@ func (suite *KeeperTestSuite) TestMsgServer_DeleteRelationship() {
 				sdk.NewEvent(
 					sdk.EventTypeMessage,
 					sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory),
+					sdk.NewAttribute(sdk.AttributeKeyAction, sdk.MsgTypeURL(&types.MsgDeleteRelationship{})),
 					sdk.NewAttribute(sdk.AttributeKeySender, "cosmos1y54exmx84cqtasvjnskf9f63djuuj68p7hqf47"),
 				),
 				sdk.NewEvent(
-					types.EventTypeRelationshipsDeleted,
+					types.EventTypeRelationshipDeleted,
 					sdk.NewAttribute(types.AttributeRelationshipCreator, "cosmos1y54exmx84cqtasvjnskf9f63djuuj68p7hqf47"),
 					sdk.NewAttribute(types.AttributeRelationshipCounterparty, "cosmos1cjf97gpzwmaf30pzvaargfgr884mpp5ak8f7ns"),
 					sdk.NewAttribute(types.AttributeKeySubspace, "1"),
@@ -319,6 +321,7 @@ func (suite *KeeperTestSuite) TestMsgServer_BlockUser() {
 				sdk.NewEvent(
 					sdk.EventTypeMessage,
 					sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory),
+					sdk.NewAttribute(sdk.AttributeKeyAction, sdk.MsgTypeURL(&types.MsgBlockUser{})),
 					sdk.NewAttribute(sdk.AttributeKeySender, "cosmos1y54exmx84cqtasvjnskf9f63djuuj68p7hqf47"),
 				),
 				sdk.NewEvent(
@@ -431,6 +434,7 @@ func (suite *KeeperTestSuite) TestMsgServer_UnblockUser() {
 				sdk.NewEvent(
 					sdk.EventTypeMessage,
 					sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory),
+					sdk.NewAttribute(sdk.AttributeKeyAction, sdk.MsgTypeURL(&types.MsgUnblockUser{})),
 					sdk.NewAttribute(sdk.AttributeKeySender, "cosmos1y54exmx84cqtasvjnskf9f63djuuj68p7hqf47"),
 				),
 				sdk.NewEvent(
diff --git a/x/relationships/legacy/v2/store_test.go b/x/relationships/legacy/v2/store_test.go
new file mode 100644
index 00000000..1f620e97
--- /dev/null
+++ b/x/relationships/legacy/v2/store_test.go
@@ -0,0 +1,115 @@
+package v2_test
+
+import (
+	"testing"
+
+	v2 "github.com/desmos-labs/desmos/v3/x/relationships/legacy/v2"
+
+	"github.com/cosmos/cosmos-sdk/testutil"
+	sdk "github.com/cosmos/cosmos-sdk/types"
+	"github.com/stretchr/testify/require"
+
+	"github.com/desmos-labs/desmos/v3/app"
+	v1 "github.com/desmos-labs/desmos/v3/x/relationships/legacy/v1"
+	"github.com/desmos-labs/desmos/v3/x/relationships/types"
+)
+
+func TestMigrateStore(t *testing.T) {
+	cdc, _ := app.MakeCodecs()
+	storeKey := sdk.NewKVStoreKey(types.StoreKey)
+	testCases := []struct {
+		name      string
+		store     func(ctx sdk.Context)
+		shouldErr bool
+		check     func(ctx sdk.Context)
+	}{
+		{
+			name: "relationships are migrated properly",
+			store: func(ctx sdk.Context) {
+				store := ctx.KVStore(storeKey)
+
+				relBz := cdc.MustMarshal(&types.Relationship{
+					Creator:      "user",
+					Counterparty: "counterparty",
+					SubspaceID:   1,
+				})
+				store.Set(v1.RelationshipsStoreKey("user", "counterparty", 1), relBz)
+			},
+			shouldErr: false,
+			check: func(ctx sdk.Context) {
+				store := ctx.KVStore(storeKey)
+
+				// Make sure the old keys are deleted properly
+				v1Key := v1.RelationshipsStoreKey("user", "counterparty", 1)
+				require.False(t, store.Has(v1Key))
+
+				v2Key := types.RelationshipsStoreKey("user", "counterparty", 1)
+				require.True(t, store.Has(v2Key))
+
+				var stored types.Relationship
+				err := cdc.Unmarshal(store.Get(v2Key), &stored)
+				require.NoError(t, err)
+				require.Equal(t, types.Relationship{
+					Creator:      "user",
+					Counterparty: "counterparty",
+					SubspaceID:   1,
+				}, stored)
+			},
+		},
+		{
+			name: "user blocks are migrated properly",
+			store: func(ctx sdk.Context) {
+				store := ctx.KVStore(storeKey)
+
+				blockBz := cdc.MustMarshal(&types.UserBlock{
+					Blocker:    "blocker",
+					Blocked:    "blocked",
+					Reason:     "reason",
+					SubspaceID: 1,
+				})
+				store.Set(v1.UserBlockStoreKey("blocker", "blocked", 1), blockBz)
+			},
+			shouldErr: false,
+			check: func(ctx sdk.Context) {
+				store := ctx.KVStore(storeKey)
+
+				// Make sure the old keys are deleted properly
+				v1Key := v1.UserBlockStoreKey("blocker", "blocked", 1)
+				require.False(t, store.Has(v1Key))
+
+				v2Key := types.UserBlockStoreKey("blocker", "blocked", 1)
+				require.True(t, store.Has(v2Key))
+
+				var stored types.UserBlock
+				err := cdc.Unmarshal(store.Get(v2Key), &stored)
+				require.NoError(t, err)
+				require.Equal(t, types.UserBlock{
+					Blocker:    "blocker",
+					Blocked:    "blocked",
+					Reason:     "reason",
+					SubspaceID: 1,
+				}, stored)
+			},
+		},
+	}
+
+	for _, tc := range testCases {
+		tc := tc
+		t.Run(tc.name, func(t *testing.T) {
+			ctx := testutil.DefaultContext(storeKey, sdk.NewTransientStoreKey("test"))
+			if tc.store != nil {
+				tc.store(ctx)
+			}
+
+			err := v2.MigrateStore(ctx, storeKey, cdc)
+			if tc.shouldErr {
+				require.Error(t, err)
+			} else {
+				require.NoError(t, err)
+				if tc.check != nil {
+					tc.check(ctx)
+				}
+			}
+		})
+	}
+}
diff --git a/x/subspaces/keeper/msg_server_test.go b/x/subspaces/keeper/msg_server_test.go
index 68096b66..212b04a3 100644
--- a/x/subspaces/keeper/msg_server_test.go
+++ b/x/subspaces/keeper/msg_server_test.go
@@ -65,6 +65,7 @@ func (suite *KeeperTestsuite) TestMsgServer_CreateSubspace() {
 				sdk.NewEvent(
 					sdk.EventTypeMessage,
 					sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory),
+					sdk.NewAttribute(sdk.AttributeKeyAction, sdk.MsgTypeURL(&types.MsgCreateSubspace{})),
 					sdk.NewAttribute(sdk.AttributeKeySender, "cosmos1qzskhrcjnkdz2ln4yeafzsdwht8ch08j4wed69"),
 				),
 				sdk.NewEvent(
@@ -119,6 +120,7 @@ func (suite *KeeperTestsuite) TestMsgServer_CreateSubspace() {
 				sdk.NewEvent(
 					sdk.EventTypeMessage,
 					sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory),
+					sdk.NewAttribute(sdk.AttributeKeyAction, sdk.MsgTypeURL(&types.MsgCreateSubspace{})),
 					sdk.NewAttribute(sdk.AttributeKeySender, "cosmos18atyyv6zycryhvnhpr2mjxgusdcah6kdpkffq0"),
 				),
 				sdk.NewEvent(
@@ -179,6 +181,7 @@ func (suite *KeeperTestsuite) TestMsgServer_CreateSubspace() {
 				sdk.NewEvent(
 					sdk.EventTypeMessage,
 					sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory),
+					sdk.NewAttribute(sdk.AttributeKeyAction, sdk.MsgTypeURL(&types.MsgCreateSubspace{})),
 					sdk.NewAttribute(sdk.AttributeKeySender, "cosmos1y4emx0mm4ncva9mnv9yvjrm7nrq3psvmwhk9ll"),
 				),
 				sdk.NewEvent(
@@ -371,6 +374,7 @@ func (suite *KeeperTestsuite) TestMsgServer_EditSubspace() {
 				sdk.NewEvent(
 					sdk.EventTypeMessage,
 					sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory),
+					sdk.NewAttribute(sdk.AttributeKeyAction, sdk.MsgTypeURL(&types.MsgEditSubspace{})),
 					sdk.NewAttribute(sdk.AttributeKeySender, "cosmos1m0czrla04f7rp3zg7dsgc4kla54q7pc4xt00l5"),
 				),
 				sdk.NewEvent(
@@ -492,6 +496,7 @@ func (suite *KeeperTestsuite) TestMsgServer_DeleteSubspace() {
 				sdk.NewEvent(
 					sdk.EventTypeMessage,
 					sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory),
+					sdk.NewAttribute(sdk.AttributeKeyAction, sdk.MsgTypeURL(&types.MsgDeleteSubspace{})),
 					sdk.NewAttribute(sdk.AttributeKeySender, "cosmos1m0czrla04f7rp3zg7dsgc4kla54q7pc4xt00l5"),
 				),
 				sdk.NewEvent(
@@ -675,6 +680,7 @@ func (suite *KeeperTestsuite) TestMsgServer_CreateUserGroup() {
 				sdk.NewEvent(
 					sdk.EventTypeMessage,
 					sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory),
+					sdk.NewAttribute(sdk.AttributeKeyAction, sdk.MsgTypeURL(&types.MsgCreateUserGroup{})),
 					sdk.NewAttribute(sdk.AttributeKeySender, "cosmos1x5pjlvufs4znnhhkwe8v4tw3kz30f3lxgwza53"),
 				),
 				sdk.NewEvent(
@@ -857,6 +863,7 @@ func (suite *KeeperTestsuite) TestMsgServer_EditUserGroup() {
 				sdk.NewEvent(
 					sdk.EventTypeMessage,
 					sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory),
+					sdk.NewAttribute(sdk.AttributeKeyAction, sdk.MsgTypeURL(&types.MsgEditUserGroup{})),
 					sdk.NewAttribute(sdk.AttributeKeySender, "cosmos1x5pjlvufs4znnhhkwe8v4tw3kz30f3lxgwza53"),
 				),
 				sdk.NewEvent(
@@ -1077,6 +1084,7 @@ func (suite *KeeperTestsuite) TestMsgServer_SetUserGroupPermissions() {
 				sdk.NewEvent(
 					sdk.EventTypeMessage,
 					sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory),
+					sdk.NewAttribute(sdk.AttributeKeyAction, sdk.MsgTypeURL(&types.MsgSetUserGroupPermissions{})),
 					sdk.NewAttribute(sdk.AttributeKeySender, "cosmos1m0czrla04f7rp3zg7dsgc4kla54q7pc4xt00l5"),
 				),
 				sdk.NewEvent(
@@ -1127,6 +1135,7 @@ func (suite *KeeperTestsuite) TestMsgServer_SetUserGroupPermissions() {
 				sdk.NewEvent(
 					sdk.EventTypeMessage,
 					sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory),
+					sdk.NewAttribute(sdk.AttributeKeyAction, sdk.MsgTypeURL(&types.MsgSetUserGroupPermissions{})),
 					sdk.NewAttribute(sdk.AttributeKeySender, "cosmos1x5pjlvufs4znnhhkwe8v4tw3kz30f3lxgwza53"),
 				),
 				sdk.NewEvent(
@@ -1269,6 +1278,7 @@ func (suite *KeeperTestsuite) TestMsgServer_DeleteUserGroup() {
 				sdk.NewEvent(
 					sdk.EventTypeMessage,
 					sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory),
+					sdk.NewAttribute(sdk.AttributeKeyAction, sdk.MsgTypeURL(&types.MsgDeleteUserGroup{})),
 					sdk.NewAttribute(sdk.AttributeKeySender, "cosmos1x5pjlvufs4znnhhkwe8v4tw3kz30f3lxgwza53"),
 				),
 				sdk.NewEvent(
@@ -1447,6 +1457,7 @@ func (suite *KeeperTestsuite) TestMsgServer_AddUserToGroup() {
 				sdk.NewEvent(
 					sdk.EventTypeMessage,
 					sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory),
+					sdk.NewAttribute(sdk.AttributeKeyAction, sdk.MsgTypeURL(&types.MsgAddUserToUserGroup{})),
 					sdk.NewAttribute(sdk.AttributeKeySender, "cosmos1x5pjlvufs4znnhhkwe8v4tw3kz30f3lxgwza53"),
 				),
 				sdk.NewEvent(
@@ -1629,6 +1640,7 @@ func (suite *KeeperTestsuite) TestMsgServer_RemoveUserFromGroup() {
 				sdk.NewEvent(
 					sdk.EventTypeMessage,
 					sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory),
+					sdk.NewAttribute(sdk.AttributeKeyAction, sdk.MsgTypeURL(&types.MsgRemoveUserFromUserGroup{})),
 					sdk.NewAttribute(sdk.AttributeKeySender, "cosmos1x5pjlvufs4znnhhkwe8v4tw3kz30f3lxgwza53"),
 				),
 				sdk.NewEvent(
@@ -1767,6 +1779,7 @@ func (suite *KeeperTestsuite) TestMsgServer_SetUserPermissions() {
 				sdk.NewEvent(
 					sdk.EventTypeMessage,
 					sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory),
+					sdk.NewAttribute(sdk.AttributeKeyAction, sdk.MsgTypeURL(&types.MsgSetUserPermissions{})),
 					sdk.NewAttribute(sdk.AttributeKeySender, "cosmos17ua98rre5j9ce7hfude0y5y3rh4gtqkygm8hru"),
 				),
 				sdk.NewEvent(