From 208100e52a07a2bf591f677615fe9c47e9d798db Mon Sep 17 00:00:00 2001
From: crStiv <cryptostiv7@gmail.com>
Date: Fri, 20 Jun 2025 20:13:01 +0200
Subject: [PATCH 1/6] Update keys.go

---
 modules/apps/rate-limiting/types/keys.go | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/modules/apps/rate-limiting/types/keys.go b/modules/apps/rate-limiting/types/keys.go
index 1ba017419bd..ea105b97c9c 100644
--- a/modules/apps/rate-limiting/types/keys.go
+++ b/modules/apps/rate-limiting/types/keys.go
@@ -26,11 +26,14 @@ var (
 	RateLimitKeyPrefix      = bytes("rate-limit")
 	PendingSendPacketPrefix = bytes("pending-send-packet")
 	DenomBlacklistKeyPrefix = bytes("denom-blacklist")
-	// TODO: Fix IBCGO-2368
-	AddressWhitelistKeyPrefix = bytes("address-blacklist")
+	// Fixed IBCGO-2368: Changed from "address-blacklist" to "address-whitelist"
+	AddressWhitelistKeyPrefix = bytes("address-whitelist")
 	HourEpochKey              = bytes("hour-epoch")
 
 	PendingSendPacketChannelLength = 16
+
+	// Legacy key for migration purposes
+	LegacyAddressWhitelistKeyPrefix = bytes("address-blacklist")
 )
 
 // Get the rate limit byte key built from the denom and channelId

From bf6a1ad2beafc3fddb19bb661da44f1b60fc5762 Mon Sep 17 00:00:00 2001
From: crStiv <cryptostiv7@gmail.com>
Date: Fri, 20 Jun 2025 20:13:16 +0200
Subject: [PATCH 2/6] Update module.go

---
 modules/apps/rate-limiting/module.go | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/modules/apps/rate-limiting/module.go b/modules/apps/rate-limiting/module.go
index 5834ad09b07..4de9cab0fd8 100644
--- a/modules/apps/rate-limiting/module.go
+++ b/modules/apps/rate-limiting/module.go
@@ -108,6 +108,11 @@ func NewAppModule(k keeper.Keeper) AppModule {
 func (am AppModule) RegisterServices(cfg module.Configurator) {
 	types.RegisterMsgServer(cfg.MsgServer(), keeper.NewMsgServerImpl(am.keeper)) // Use the msgServer implementation
 	types.RegisterQueryServer(cfg.QueryServer(), am.keeper)
+
+	migrator := keeper.NewMigrator(&am.keeper)
+	if err := cfg.RegisterMigration(types.ModuleName, 1, migrator.Migrate1to2); err != nil {
+		panic(fmt.Sprintf("failed to migrate rate-limiting from version 1 to 2: %v", err))
+	}
 }
 
 // InitGenesis performs genesis initialization for the rate-limiting module. It returns
@@ -126,7 +131,7 @@ func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) json.Raw
 }
 
 // ConsensusVersion implements AppModule/ConsensusVersion defining the current version of rate-limiting.
-func (AppModule) ConsensusVersion() uint64 { return 1 }
+func (AppModule) ConsensusVersion() uint64 { return 2 }
 
 // BeginBlock implements the AppModule interface
 func (am AppModule) BeginBlock(ctx context.Context) error {

From 8c1fd615550198c6333777bd46e132bae4a90f70 Mon Sep 17 00:00:00 2001
From: crStiv <cryptostiv7@gmail.com>
Date: Fri, 20 Jun 2025 20:13:36 +0200
Subject: [PATCH 3/6] Create migrations.go

---
 .../apps/rate-limiting/keeper/migrations.go   | 23 +++++++++++++++++++
 1 file changed, 23 insertions(+)
 create mode 100644 modules/apps/rate-limiting/keeper/migrations.go

diff --git a/modules/apps/rate-limiting/keeper/migrations.go b/modules/apps/rate-limiting/keeper/migrations.go
new file mode 100644
index 00000000000..561930f0444
--- /dev/null
+++ b/modules/apps/rate-limiting/keeper/migrations.go
@@ -0,0 +1,23 @@
+package keeper
+
+import (
+	sdk "github.com/cosmos/cosmos-sdk/types"
+
+	v2 "github.com/cosmos/ibc-go/v10/modules/apps/rate-limiting/migrations/v2"
+)
+
+// Migrator is a struct for handling in-place store migrations.
+type Migrator struct {
+	keeper *Keeper
+}
+
+// NewMigrator returns a new Migrator.
+func NewMigrator(keeper *Keeper) Migrator {
+	return Migrator{keeper: keeper}
+}
+
+// Migrate1to2 migrates the rate-limiting store from v1 to v2 by:
+// - Migrating whitelist entries from the incorrect "address-blacklist" prefix to the correct "address-whitelist" prefix
+func (m Migrator) Migrate1to2(ctx sdk.Context) error {
+	return v2.MigrateStore(ctx, m.keeper.storeService, m.keeper.cdc)
+}

From e94de4b2f318585706a9ce3d7127ec28994b790c Mon Sep 17 00:00:00 2001
From: crStiv <cryptostiv7@gmail.com>
Date: Fri, 20 Jun 2025 20:15:21 +0200
Subject: [PATCH 4/6] Create store.go

---
 modules/apps/rate-limiting/keeper/v2/store.go | 53 +++++++++++++++++++
 1 file changed, 53 insertions(+)
 create mode 100644 modules/apps/rate-limiting/keeper/v2/store.go

diff --git a/modules/apps/rate-limiting/keeper/v2/store.go b/modules/apps/rate-limiting/keeper/v2/store.go
new file mode 100644
index 00000000000..6acfa499f08
--- /dev/null
+++ b/modules/apps/rate-limiting/keeper/v2/store.go
@@ -0,0 +1,53 @@
+package v2
+
+import (
+	"cosmossdk.io/core/store"
+	storetypes "cosmossdk.io/store/types"
+
+	"github.com/cosmos/cosmos-sdk/codec"
+	"github.com/cosmos/cosmos-sdk/runtime"
+	sdk "github.com/cosmos/cosmos-sdk/types"
+
+	"github.com/cosmos/ibc-go/v10/modules/apps/rate-limiting/types"
+)
+
+// MigrateStore migrates the rate-limiting store from v1 to v2 by:
+// - Migrating whitelist entries from the incorrect "address-blacklist" prefix to the correct "address-whitelist" prefix
+func MigrateStore(ctx sdk.Context, storeService store.KVStoreService, cdc codec.BinaryCodec) error {
+	kvStore := storeService.OpenKVStore(ctx)
+	return migrateAddressWhitelistKeys(runtime.KVStoreAdapter(kvStore), cdc)
+}
+
+// migrateAddressWhitelistKeys migrates whitelist entries from the legacy key prefix to the correct key prefix
+func migrateAddressWhitelistKeys(store storetypes.KVStore, cdc codec.BinaryCodec) error {
+	// Get all entries with the legacy prefix
+	iterator := storetypes.KVStorePrefixIterator(store, types.LegacyAddressWhitelistKeyPrefix)
+	defer iterator.Close()
+
+	// Collect all entries that need to be migrated
+	var entries []types.WhitelistedAddressPair
+	var keysToDelete [][]byte
+
+	for ; iterator.Valid(); iterator.Next() {
+		var whitelist types.WhitelistedAddressPair
+		if err := cdc.Unmarshal(iterator.Value(), &whitelist); err != nil {
+			return err
+		}
+		entries = append(entries, whitelist)
+		keysToDelete = append(keysToDelete, iterator.Key())
+	}
+
+	// Set entries with the new prefix
+	for _, whitelist := range entries {
+		newKey := append(types.AddressWhitelistKeyPrefix, types.AddressWhitelistKey(whitelist.Sender, whitelist.Receiver)...)
+		value := cdc.MustMarshal(&whitelist)
+		store.Set(newKey, value)
+	}
+
+	// Delete old entries
+	for _, key := range keysToDelete {
+		store.Delete(key)
+	}
+
+	return nil
+}

From 69b558f513697a9d0a39f74f958a582c82c6ede3 Mon Sep 17 00:00:00 2001
From: crStiv <cryptostiv7@gmail.com>
Date: Fri, 20 Jun 2025 20:15:41 +0200
Subject: [PATCH 5/6] Create store_test.go

---
 .../rate-limiting/keeper/v2/store_test.go     | 107 ++++++++++++++++++
 1 file changed, 107 insertions(+)
 create mode 100644 modules/apps/rate-limiting/keeper/v2/store_test.go

diff --git a/modules/apps/rate-limiting/keeper/v2/store_test.go b/modules/apps/rate-limiting/keeper/v2/store_test.go
new file mode 100644
index 00000000000..eed9b3a34f3
--- /dev/null
+++ b/modules/apps/rate-limiting/keeper/v2/store_test.go
@@ -0,0 +1,107 @@
+package v2_test
+
+import (
+	"testing"
+
+	testifysuite "github.com/stretchr/testify/suite"
+
+	storetypes "cosmossdk.io/store/types"
+
+	"github.com/cosmos/cosmos-sdk/codec"
+	"github.com/cosmos/cosmos-sdk/runtime"
+
+	v2 "github.com/cosmos/ibc-go/v10/modules/apps/rate-limiting/migrations/v2"
+	"github.com/cosmos/ibc-go/v10/modules/apps/rate-limiting/types"
+	ibctesting "github.com/cosmos/ibc-go/v10/testing"
+)
+
+type MigrationsV2TestSuite struct {
+	testifysuite.Suite
+
+	coordinator *ibctesting.Coordinator
+	chainA      *ibctesting.TestChain
+	cdc         codec.BinaryCodec
+}
+
+func (suite *MigrationsV2TestSuite) SetupTest() {
+	suite.coordinator = ibctesting.NewCoordinator(suite.T(), 1)
+	suite.chainA = suite.coordinator.GetChain(ibctesting.GetChainID(1))
+	suite.cdc = suite.chainA.App.AppCodec()
+}
+
+func TestMigrationsV2TestSuite(t *testing.T) {
+	testifysuite.Run(t, new(MigrationsV2TestSuite))
+}
+
+func (suite *MigrationsV2TestSuite) TestMigrateStore() {
+	ctx := suite.chainA.GetContext()
+	storeService := runtime.NewKVStoreService(suite.chainA.GetSimApp().GetKey(types.StoreKey))
+	store := runtime.KVStoreAdapter(storeService.OpenKVStore(ctx))
+
+	// Create test whitelist entries using the legacy prefix
+	whitelistPairs := []types.WhitelistedAddressPair{
+		{
+			Sender:   "cosmos1abc123",
+			Receiver: "cosmos1def456",
+		},
+		{
+			Sender:   "cosmos1ghi789",
+			Receiver: "cosmos1jkl012",
+		},
+	}
+
+	// Store entries with the legacy prefix
+	for _, pair := range whitelistPairs {
+		key := append(types.LegacyAddressWhitelistKeyPrefix, types.AddressWhitelistKey(pair.Sender, pair.Receiver)...)
+		value := suite.cdc.MustMarshal(&pair)
+		store.Set(key, value)
+	}
+
+	// Verify entries exist with legacy prefix
+	for _, pair := range whitelistPairs {
+		key := append(types.LegacyAddressWhitelistKeyPrefix, types.AddressWhitelistKey(pair.Sender, pair.Receiver)...)
+		suite.Require().True(store.Has(key))
+	}
+
+	// Run migration
+	err := v2.MigrateStore(ctx, storeService, suite.cdc)
+	suite.Require().NoError(err)
+
+	// Verify entries no longer exist with legacy prefix
+	for _, pair := range whitelistPairs {
+		key := append(types.LegacyAddressWhitelistKeyPrefix, types.AddressWhitelistKey(pair.Sender, pair.Receiver)...)
+		suite.Require().False(store.Has(key))
+	}
+
+	// Verify entries exist with new prefix
+	for _, pair := range whitelistPairs {
+		key := append(types.AddressWhitelistKeyPrefix, types.AddressWhitelistKey(pair.Sender, pair.Receiver)...)
+		suite.Require().True(store.Has(key))
+
+		// Verify the value is preserved correctly
+		value := store.Get(key)
+		var retrievedPair types.WhitelistedAddressPair
+		suite.cdc.MustUnmarshal(value, &retrievedPair)
+		suite.Require().Equal(pair.Sender, retrievedPair.Sender)
+		suite.Require().Equal(pair.Receiver, retrievedPair.Receiver)
+	}
+}
+
+func (suite *MigrationsV2TestSuite) TestMigrateStoreEmptyStore() {
+	ctx := suite.chainA.GetContext()
+	storeService := runtime.NewKVStoreService(suite.chainA.GetSimApp().GetKey(types.StoreKey))
+
+	// Run migration on empty store
+	err := v2.MigrateStore(ctx, storeService, suite.cdc)
+	suite.Require().NoError(err)
+
+	// Verify no entries exist
+	store := runtime.KVStoreAdapter(storeService.OpenKVStore(ctx))
+	iterator := storetypes.KVStorePrefixIterator(store, types.LegacyAddressWhitelistKeyPrefix)
+	defer iterator.Close()
+	suite.Require().False(iterator.Valid())
+
+	iterator = storetypes.KVStorePrefixIterator(store, types.AddressWhitelistKeyPrefix)
+	defer iterator.Close()
+	suite.Require().False(iterator.Valid())
+}

From 4a40462b0c1eb3bc1e53c56e12bb35672744df2e Mon Sep 17 00:00:00 2001
From: crStiv <cryptostiv7@gmail.com>
Date: Fri, 20 Jun 2025 20:15:59 +0200
Subject: [PATCH 6/6] Update CHANGELOG.md

---
 CHANGELOG.md | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 7891301c7c6..e204b5a756a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -56,6 +56,8 @@ Ref: https://keepachangelog.com/en/1.0.0/
 
 ### Bug Fixes
 
+* (apps/rate-limiting) [\#8546](https://github.com/cosmos/ibc-go/issues/8546) Fix incorrect `AddressWhitelistKeyPrefix` key name from "address-blacklist" to "address-whitelist".
+
 ### Testing API
 
 * [\#8366](https://github.com/cosmos/ibc-go/pull/8366) - Replaced the deprecated `codec.ProtoMarshaler` interface with `proto.Message`.
@@ -75,6 +77,8 @@ Ref: https://keepachangelog.com/en/1.0.0/
 
 ### State Machine Breaking
 
+* (apps/rate-limiting) [\#8546](https://github.com/cosmos/ibc-go/issues/8546) Migrate address whitelist store keys from incorrect "address-blacklist" prefix to correct "address-whitelist" prefix.
+
 ### Improvements
 
 * (core/api) [\#8303](https://github.com/cosmos/ibc-go/pull/8303) Prefix-based routing in IBCv2 Router