Skip to content

Commit

Permalink
feat: configurable fee collector for DeductFeeDecorator (#407)
Browse files Browse the repository at this point in the history
* feat: configurable fee collector for DeductFeeDecorator

* docs: update changelog with PR number

* test: ensure increment of alt account, comments
  • Loading branch information
JimLarson authored and JeancarloBarrios committed Sep 28, 2024
1 parent 07fabc1 commit e7e32bd
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 22 deletions.
6 changes: 5 additions & 1 deletion CHANGELOG-Agoric.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,11 @@ Ref: https://keepachangelog.com/en/1.0.0/

## Unreleased

### API Breaking Changes
### Improvements

* (auth) [#407](https://github.com/agoric-labs/cosmos-sdk/pull/407) Configurable fee collector module account in DeductFeeDecorator.

### API Breaking

* (auth, bank) Agoric/agoric-sdk#8989 Remove deprecated lien support

Expand Down
48 changes: 28 additions & 20 deletions x/auth/ante/fee.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,24 +23,30 @@ type TxFeeChecker func(ctx context.Context, tx transaction.Tx) (sdk.Coins, int64
// Call next AnteHandler if fees are successfully deducted.
// CONTRACT: The Tx must implement the FeeTx interface to use DeductFeeDecorator.
type DeductFeeDecorator struct {
accountKeeper AccountKeeper
bankKeeper types.BankKeeper
feegrantKeeper FeegrantKeeper
txFeeChecker TxFeeChecker
minGasPrices sdk.DecCoins
accountKeeper AccountKeeper
bankKeeper types.BankKeeper
feegrantKeeper FeegrantKeeper
txFeeChecker TxFeeChecker
feeCollectorName string
}

func NewDeductFeeDecorator(ak AccountKeeper, bk types.BankKeeper, fk FeegrantKeeper, tfc TxFeeChecker) *DeductFeeDecorator {
dfd := &DeductFeeDecorator{
accountKeeper: ak,
bankKeeper: bk,
feegrantKeeper: fk,
txFeeChecker: tfc,
minGasPrices: sdk.NewDecCoins(),
}
func NewDeductFeeDecorator(ak AccountKeeper, bk types.BankKeeper, fk FeegrantKeeper, tfc TxFeeChecker) DeductFeeDecorator {
return NewDeductFeeDecoratorWithName(ak, bk, fk, tfc, types.FeeCollectorName)
}

// NewDeductFeeDecoratorWithName returns a DeductFeeDecorator using a custom fee collector module account.
// Agoric note: for collecting fees in the reserve account.
func NewDeductFeeDecoratorWithName(ak AccountKeeper, bk types.BankKeeper, fk FeegrantKeeper, tfc TxFeeChecker, feeCollectorName string) DeductFeeDecorator {
if tfc == nil {
dfd.txFeeChecker = dfd.checkTxFeeWithValidatorMinGasPrices
tfc = checkTxFeeWithValidatorMinGasPrices
}

return DeductFeeDecorator{
accountKeeper: ak,
bankKeeper: bk,
feegrantKeeper: fk,
txFeeChecker: tfc,
feeCollectorName: feeCollectorName,
}

return dfd
Expand Down Expand Up @@ -91,8 +97,8 @@ func (dfd *DeductFeeDecorator) innerValidateTx(ctx context.Context, tx transacti
}
}

if addr := dfd.accountKeeper.GetModuleAddress(types.FeeCollectorName); addr == nil {
return fmt.Errorf("fee collector module account (%s) has not been set", types.FeeCollectorName)
if addr := dfd.accountKeeper.GetModuleAddress(dfd.feeCollectorName); addr == nil {
return fmt.Errorf("fee collector module account (%s) has not been set", dfd.feeCollectorName)
}

feePayer := feeTx.FeePayer()
Expand Down Expand Up @@ -123,7 +129,8 @@ func (dfd *DeductFeeDecorator) innerValidateTx(ctx context.Context, tx transacti

// deduct the fees
if !fee.IsZero() {
if err := DeductFees(dfd.bankKeeper, ctx, deductFeesFrom, fee); err != nil {
err := DeductFees(dfd.bankKeeper, ctx, deductFeesFromAcc, fee, dfd.feeCollectorName)
if err != nil {
return err
}
}
Expand All @@ -141,13 +148,14 @@ func (dfd *DeductFeeDecorator) innerValidateTx(ctx context.Context, tx transacti
}

// DeductFees deducts fees from the given account.
func DeductFees(bankKeeper types.BankKeeper, ctx context.Context, acc []byte, fees sdk.Coins) error {
func DeductFees(bankKeeper types.BankKeeper, ctx sdk.Context, acc types.AccountI, fees sdk.Coins, feeCollectorName string) error {
if !fees.IsValid() {
return errorsmod.Wrapf(sdkerrors.ErrInsufficientFee, "invalid fee amount: %s", fees)
}

if err := bankKeeper.SendCoinsFromAccountToModule(ctx, acc, types.FeeCollectorName, fees); err != nil {
return fmt.Errorf("failed to deduct fees: %w", err)
err := bankKeeper.SendCoinsFromAccountToModule(ctx, acc.GetAddress(), feeCollectorName, fees)
if err != nil {
return sdkerrors.Wrapf(sdkerrors.ErrInsufficientFunds, err.Error())
}

return nil
Expand Down
48 changes: 47 additions & 1 deletion x/auth/ante/fee_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ import (
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/cosmos/cosmos-sdk/types/tx/signing"
"github.com/cosmos/cosmos-sdk/x/auth/ante"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
"github.com/cosmos/cosmos-sdk/x/auth/types"
"github.com/cosmos/cosmos-sdk/x/bank/testutil"
)

func (s *AnteTestSuite) TestDeductFeeDecorator_ZeroGas() {
Expand Down Expand Up @@ -155,3 +156,48 @@ func (s *AnteTestSuite) TestDeductFees() {

s.Require().Nil(err, "Tx errored after account has been set with sufficient funds")
}

func (s *AnteTestSuite) TestDeductFees_WithName() {
s.SetupTest(false) // setup
s.txBuilder = s.clientCtx.TxConfig.NewTxBuilder()

// keys and addresses
priv1, _, addr1 := testdata.KeyTestPubAddr()

// msg and signatures
msg := testdata.NewTestMsg(addr1)
feeAmount := testdata.NewTestFeeAmount()
gasLimit := testdata.NewTestGasLimit()
s.Require().NoError(s.txBuilder.SetMsgs(msg))
s.txBuilder.SetFeeAmount(feeAmount)
s.txBuilder.SetGasLimit(gasLimit)

privs, accNums, accSeqs := []cryptotypes.PrivKey{priv1}, []uint64{0}, []uint64{0}
tx, err := s.CreateTestTx(privs, accNums, accSeqs, s.ctx.ChainID())
s.Require().NoError(err)

// Set transacting account with sufficient funds
acc := s.app.AccountKeeper.NewAccountWithAddress(s.ctx, addr1)
s.app.AccountKeeper.SetAccount(s.ctx, acc)
coins := sdk.NewCoins(sdk.NewCoin("atom", sdk.NewInt(200)))
err = testutil.FundAccount(s.app.BankKeeper, s.ctx, addr1, coins)
s.Require().NoError(err)

feeCollectorAcc := s.app.AccountKeeper.GetModuleAccount(s.ctx, types.FeeCollectorName)
// pick a simapp module account
altCollectorName := "distribution"
altCollectorAcc := s.app.AccountKeeper.GetModuleAccount(s.ctx, altCollectorName)
s.Require().True(s.app.BankKeeper.GetAllBalances(s.ctx, feeCollectorAcc.GetAddress()).Empty())
altBalance := s.app.BankKeeper.GetAllBalances(s.ctx, altCollectorAcc.GetAddress())

// Run the transaction through a handler chain that deducts fees into altCollectorAcc.
dfd := ante.NewDeductFeeDecoratorWithName(s.app.AccountKeeper, s.app.BankKeeper, nil, nil, altCollectorName)
antehandler := sdk.ChainAnteDecorators(dfd)
_, err = antehandler(s.ctx, tx, false)
s.Require().NoError(err)

s.Require().True(s.app.BankKeeper.GetAllBalances(s.ctx, feeCollectorAcc.GetAddress()).Empty())
newAltBalance := s.app.BankKeeper.GetAllBalances(s.ctx, altCollectorAcc.GetAddress())
s.Require().True(newAltBalance.IsAllGTE(altBalance))
s.Require().False(newAltBalance.IsEqual(altBalance))
}

0 comments on commit e7e32bd

Please sign in to comment.