Skip to content

Commit

Permalink
track burned fee
Browse files Browse the repository at this point in the history
  • Loading branch information
haiyizxx committed Jan 29, 2025
1 parent b596a50 commit b0f58dd
Show file tree
Hide file tree
Showing 6 changed files with 111 additions and 33 deletions.
2 changes: 1 addition & 1 deletion app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -713,7 +713,7 @@ func initMessageAnteDecorators(encodingConfig axelarParams.EncodingConfig, keepe
func InitModuleAccountPermissions() map[string][]string {
return map[string][]string{
authtypes.FeeCollectorName: nil,
distrtypes.ModuleName: {authtypes.Burner},
distrtypes.ModuleName: {authtypes.Minter, authtypes.Burner},
minttypes.ModuleName: {authtypes.Minter},
stakingtypes.BondedPoolName: {authtypes.Burner, authtypes.Staking},
stakingtypes.NotBondedPoolName: {authtypes.Burner, authtypes.Staking},
Expand Down
41 changes: 10 additions & 31 deletions x/distribution/keeper/keeper.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package keeper

import (
"fmt"

sdk "github.com/cosmos/cosmos-sdk/types"
distribution "github.com/cosmos/cosmos-sdk/x/distribution/keeper"
distributionTypes "github.com/cosmos/cosmos-sdk/x/distribution/types"
Expand All @@ -11,6 +9,7 @@ import (
"github.com/axelarnetwork/axelar-core/utils/events"
"github.com/axelarnetwork/axelar-core/x/distribution/types"
"github.com/axelarnetwork/utils/funcs"
"github.com/axelarnetwork/utils/slices"
)

// Keeper wraps the distribution keeper to customize fee allocation mechanism
Expand Down Expand Up @@ -39,12 +38,7 @@ func NewKeeper(
// AllocateTokens modifies the fee distribution by:
// - Allocating the community tax portion to the community pool
// - Burning all remaining tokens instead of distributing to validators
func (k Keeper) AllocateTokens(
ctx sdk.Context, _, totalPreviousPower int64,
previousProposer sdk.ConsAddress, _ []abci.VoteInfo,
) {
logger := k.Logger(ctx)

func (k Keeper) AllocateTokens(ctx sdk.Context, _, _ int64, _ sdk.ConsAddress, _ []abci.VoteInfo) {
// fetch and clear the collected fees for distribution, since this is
// called in BeginBlock, collected fees will be from the previous block
// (and distributed to the previous proposer)
Expand All @@ -58,22 +52,15 @@ func (k Keeper) AllocateTokens(
panic(err)
}

// temporary workaround to keep CanWithdrawInvariant happy
// general discussions here: https://github.com/cosmos/cosmos-sdk/issues/2906#issuecomment-441867634
feePool := k.GetFeePool(ctx)
if totalPreviousPower == 0 {
feePool.CommunityPool = feePool.CommunityPool.Add(feesCollected...)
k.SetFeePool(ctx, feePool)
return
}

communityTaxRate := k.GetCommunityTax(ctx)
communityPoolAmount := feesCollected.MulDecTruncate(communityTaxRate)
remaining := feesCollected.Sub(communityPoolAmount)

// truncate the remaining coins, return remainder to community pool
feeToBurn, remainder := remaining.TruncateDecimal()
communityPoolAmount = communityPoolAmount.Add(remainder...)
feeToBurn, truncationRemainder := remaining.TruncateDecimal()
communityPoolAmount = communityPoolAmount.Add(truncationRemainder...)

// allocate community funding
feePool.CommunityPool = feePool.CommunityPool.Add(communityPoolAmount...)
Expand All @@ -85,18 +72,10 @@ func (k Keeper) AllocateTokens(
Coins: feeToBurn,
})

// keep the error log from the original implementation
proposerValidator := k.stakingKeeper.ValidatorByConsAddr(ctx, previousProposer)
if proposerValidator == nil {
// previous proposer can be unknown if say, the unbonding period is 1 block, so
// e.g. a validator undelegates at block X, it's removed entirely by
// block X+1's endblock, then X+2 we need to refer to the previous
// proposer for X+1, but we've forgotten about them.
logger.Error(fmt.Sprintf(
"WARNING: Attempt to allocate proposer rewards to unknown proposer %s. "+
"This should happen only if the proposer unbonded completely within a single block, "+
"which generally should not happen except in exceptional circumstances (or fuzz testing). "+
"We recommend you investigate immediately.",
previousProposer.String()))
}
// track cumulative burned fee
feeBurned := slices.Map(feeToBurn, func(coin sdk.Coin) sdk.Coin {
return types.ToBurned(coin)
})
funcs.MustNoErr(k.bankKeeper.MintCoins(ctx, distributionTypes.ModuleName, feeBurned))
funcs.MustNoErr(k.bankKeeper.SendCoinsFromModuleToAccount(ctx, distributionTypes.ModuleName, types.ZeroAddress, feeBurned))
}
28 changes: 27 additions & 1 deletion x/distribution/keeper/keeper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,14 @@ func TestAllocateTokens(t *testing.T) {
k keeper.Keeper
accBalances map[string]sdk.Coins
bk *mock.BankKeeperMock
fee sdk.Coins
)

ctx := sdk.NewContext(fake.NewMultiStore(), tmproto.Header{}, false, log.TestingLogger())

fee = sdk.NewCoins(sdk.NewCoin(axelarnettypes.NativeAsset, sdk.NewInt(rand.PosI64())))
accBalances = map[string]sdk.Coins{
authtypes.NewModuleAddress(authtypes.FeeCollectorName).String(): sdk.NewCoins(sdk.NewCoin(axelarnettypes.NativeAsset, sdk.NewInt(rand.PosI64()))),
authtypes.NewModuleAddress(authtypes.FeeCollectorName).String(): fee,
}

Given("an axelar distribution keeper", func() {
Expand All @@ -65,10 +67,24 @@ func TestAllocateTokens(t *testing.T) {

return nil
},
SendCoinsFromModuleToAccountFunc: func(ctx sdk.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins) error {
senderModule = authtypes.NewModuleAddress(senderModule).String()

accBalances[senderModule] = accBalances[senderModule].Sub(amt)
accBalances[recipientAddr.String()] = accBalances[recipientAddr.String()].Add(amt...)

return nil
},
BurnCoinsFunc: func(ctx sdk.Context, name string, amt sdk.Coins) error {
acc := authtypes.NewModuleAddress(name).String()
accBalances[acc] = accBalances[acc].Sub(amt)

return nil
},
MintCoinsFunc: func(ctx sdk.Context, name string, amt sdk.Coins) error {
acc := authtypes.NewModuleAddress(name).String()
accBalances[acc] = accBalances[acc].Add(amt...)

return nil
},
}
Expand Down Expand Up @@ -98,6 +114,16 @@ func TestAllocateTokens(t *testing.T) {
return e.Type == feeBurnedType
}), 1)

expectedBurnedFee := sdk.NewCoins(slices.Map(expectedBurnedFee(ctx, k, fee), types.ToBurned)...)
assert.Equal(t, expectedBurnedFee, accBalances[types.ZeroAddress.String()])
}).
Run(t)
}

func expectedBurnedFee(ctx sdk.Context, k keeper.Keeper, fee sdk.Coins) sdk.Coins {
feesDec := sdk.NewDecCoinsFromCoins(fee...)
tax := feesDec.MulDecTruncate(k.GetCommunityTax(ctx))
burnAmt, _ := feesDec.Sub(tax).TruncateDecimal()

return burnAmt
}
1 change: 1 addition & 0 deletions x/distribution/types/expected_keepers.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
type BankKeeper interface {
types.BankKeeper
BurnCoins(ctx sdk.Context, moduleName string, amt sdk.Coins) error
MintCoins(ctx sdk.Context, moduleName string, amt sdk.Coins) error
}

type AccountKeeper interface {
Expand Down
56 changes: 56 additions & 0 deletions x/distribution/types/mock/expected_keepers.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 16 additions & 0 deletions x/distribution/types/types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package types

import (
"fmt"

sdk "github.com/cosmos/cosmos-sdk/types"
)

const feeBurnedPrefix = "burned"

var ZeroAddress = sdk.AccAddress(make([]byte, 32))

// ToBurned converts a coin to a coin with 'burned' prefix
func ToBurned(coin sdk.Coin) sdk.Coin {
return sdk.NewCoin(fmt.Sprintf("%s-%s", feeBurnedPrefix, coin.Denom), coin.Amount)
}

0 comments on commit b0f58dd

Please sign in to comment.