Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,16 @@ Ref: https://keepachangelog.com/en/1.0.0/

## UNRELEASED

This patch introduces a state machine breaking change in `x/feegrant`. Revoking a grant previously attempted to delete expiration entries under the wrong store key (`prefix|grantee|granter` instead of `prefix|granter|grantee`), leaving stale queues behind. Chains must execute a software upgrade to this release so future revocations clean up the queue correctly; no additional migration scripts or manual sweeping of existing queues are required.

### Features

* (crypto/ledger) [#25435](https://github.com/cosmos/cosmos-sdk/pull/25435) Add SetDERConversion to reset skipDERConversion and App name for ledger.

### Bug Fixes

* (cli) [#25485](https://github.com/cosmos/cosmos-sdk/pull/25485) Avoid failed to convert address field in `withdraw-validator-commission` cmd.
* (x/feegrant) [#25540](https://github.com/cosmos/cosmos-sdk/pull/25540) Fix revocation cleanup by deleting expiration entries with the correct `prefix|granter|grantee` store key.

## [v0.53.4](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.53.3) - 2025-07-25

Expand Down
2 changes: 1 addition & 1 deletion x/feegrant/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ func (k Keeper) revokeAllowance(ctx context.Context, granter, grantee sdk.AccAdd
}

if exp != nil {
if err := store.Delete(feegrant.FeeAllowancePrefixQueue(exp, feegrant.FeeAllowanceKey(grantee, granter)[1:])); err != nil {
if err := store.Delete(feegrant.FeeAllowancePrefixQueue(exp, key[1:])); err != nil {
return err
}
}
Expand Down
31 changes: 31 additions & 0 deletions x/feegrant/keeper/keeper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package keeper_test

import (
"testing"
"time"

"github.com/stretchr/testify/suite"
"go.uber.org/mock/gomock"
Expand Down Expand Up @@ -32,6 +33,7 @@ type KeeperTestSuite struct {
feegrantKeeper keeper.Keeper
accountKeeper *feegranttestutil.MockAccountKeeper
bankKeeper *feegranttestutil.MockBankKeeper
storeKey storetypes.StoreKey
}

func TestKeeperTestSuite(t *testing.T) {
Expand All @@ -41,6 +43,7 @@ func TestKeeperTestSuite(t *testing.T) {
func (suite *KeeperTestSuite) SetupTest() {
suite.addrs = simtestutil.CreateIncrementalAccounts(20)
key := storetypes.NewKVStoreKey(feegrant.StoreKey)
suite.storeKey = key
testCtx := testutil.DefaultContextWithDB(suite.T(), key, storetypes.NewTransientStoreKey("transient_test"))
encCfg := moduletestutil.MakeTestEncodingConfig(module.AppModuleBasic{})

Expand Down Expand Up @@ -186,6 +189,34 @@ func (suite *KeeperTestSuite) TestKeeperCrud() {
suite.Require().NoError(err)
}

func (suite *KeeperTestSuite) TestRevokeAllowanceClearsQueue() {
expiration := suite.ctx.BlockTime().Add(24 * time.Hour)
allowance := &feegrant.BasicAllowance{
SpendLimit: suite.atom,
Expiration: &expiration,
}
err := suite.feegrantKeeper.GrantAllowance(suite.ctx, suite.addrs[0], suite.addrs[1], allowance)
suite.Require().NoError(err)
suite.Require().Equal(1, suite.feeAllowanceQueueEntryCount())
_, err = suite.msgSrvr.RevokeAllowance(suite.ctx, &feegrant.MsgRevokeAllowance{
Granter: suite.addrs[0].String(),
Grantee: suite.addrs[1].String(),
})
suite.Require().NoError(err)
suite.Require().Equal(0, suite.feeAllowanceQueueEntryCount())
}

func (suite *KeeperTestSuite) feeAllowanceQueueEntryCount() int {
store := suite.ctx.KVStore(suite.storeKey)
iterator := storetypes.KVStorePrefixIterator(store, feegrant.FeeAllowanceQueueKeyPrefix)
defer iterator.Close()
var count int
for ; iterator.Valid(); iterator.Next() {
count++
}
return count
}

func (suite *KeeperTestSuite) TestUseGrantedFee() {
eth := sdk.NewCoins(sdk.NewInt64Coin("eth", 123))
blockTime := suite.ctx.BlockTime()
Expand Down
Loading