diff --git a/x/globalfee/ante/fee.go b/x/globalfee/ante/fee.go index d99bcb261..22a4e7fcd 100644 --- a/x/globalfee/ante/fee.go +++ b/x/globalfee/ante/fee.go @@ -88,7 +88,7 @@ func (mfd FeeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, ne // if feeCoinsNoZeroDenom=[], DenomsSubsetOf returns true // if feeCoinsNoZeroDenom is not empty, but nonZeroCoinFeesReq empty, return false if !feeCoinsNonZeroDenom.DenomsSubsetOf(nonZeroCoinFeesReq) { - return ctx, errorsmod.Wrapf(sdkerrors.ErrInsufficientFee, "fee is not a subset of required fees; got %s, required: %s", feeCoins, combinedFeeRequirement) + return ctx, errorsmod.Wrapf(sdkerrors.ErrInsufficientFee, "this fee denom is not accepted; got %s, one is required: %s", feeCoins, PrettyPrint(combinedFeeRequirement)) } // Accept zero fee transactions only if both of the following statements are true: @@ -125,7 +125,16 @@ func (mfd FeeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, ne // because when nonZeroCoinFeesReq empty, and DenomsSubsetOf check passed, // the tx should already passed before) if !feeCoinsNonZeroDenom.IsAnyGTE(nonZeroCoinFeesReq) { - return ctx, errorsmod.Wrapf(sdkerrors.ErrInsufficientFee, "insufficient fees; got: %s required: %s", feeCoins, combinedFeeRequirement) + if len(feeCoins) == 0 { + return ctx, errorsmod.Wrapf(sdkerrors.ErrInsufficientFee, "no fees were specified; one fee must be provided %s", PrettyPrint(combinedFeeRequirement)) + } + + feeDiff := combinedFeeRequirement + for _, c := range feeCoins { + feeDiff = feeDiff.Sub(c) + } + + return ctx, errorsmod.Wrapf(sdkerrors.ErrInsufficientFee, "insufficient fees; only got: %s. number of coins needed: %s. one is required: %s. ", feeCoins, feeDiff, PrettyPrint(combinedFeeRequirement)) } } diff --git a/x/globalfee/ante/fee_utils.go b/x/globalfee/ante/fee_utils.go index b3d5e2c8e..6b70add32 100644 --- a/x/globalfee/ante/fee_utils.go +++ b/x/globalfee/ante/fee_utils.go @@ -1,6 +1,9 @@ package ante import ( + "encoding/json" + "fmt" + sdk "github.com/cosmos/cosmos-sdk/types" ) @@ -19,6 +22,21 @@ func ContainZeroCoins(coins sdk.Coins) bool { return false } +// PrettyPrint returns a pretty printed representation of the given coins. +func PrettyPrint(coins sdk.Coins) string { + arr := make([]string, len(coins)) + for idx, coin := range coins { + arr[idx] = fmt.Sprintf("%s%s", coin.Amount.String(), coin.Denom) + } + + bz, err := json.MarshalIndent(arr, "", " ") + if err != nil { + return "" + } + + return string(bz) +} + // CombinedFeeRequirement returns the global fee and min_gas_price combined and sorted. // Both globalFees and minGasPrices must be valid, but CombinedFeeRequirement // does not validate them, so it may return 0denom.