github.com/Finschia/finschia-sdk@v0.49.1/x/feegrant/keeper/keeper_test.go (about)

     1  package keeper_test
     2  
     3  import (
     4  	"context"
     5  	"testing"
     6  
     7  	"github.com/stretchr/testify/suite"
     8  	tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
     9  
    10  	"github.com/Finschia/finschia-sdk/simapp"
    11  	sdk "github.com/Finschia/finschia-sdk/types"
    12  	"github.com/Finschia/finschia-sdk/x/feegrant"
    13  	"github.com/Finschia/finschia-sdk/x/feegrant/keeper"
    14  )
    15  
    16  type KeeperTestSuite struct {
    17  	suite.Suite
    18  
    19  	app     *simapp.SimApp
    20  	sdkCtx  sdk.Context
    21  	addrs   []sdk.AccAddress
    22  	msgSrvr feegrant.MsgServer
    23  	ctx     context.Context
    24  	atom    sdk.Coins
    25  	keeper  keeper.Keeper
    26  }
    27  
    28  func TestKeeperTestSuite(t *testing.T) {
    29  	suite.Run(t, new(KeeperTestSuite))
    30  }
    31  
    32  func (suite *KeeperTestSuite) SetupTest() {
    33  	app := simapp.Setup(false)
    34  	ctx := app.BaseApp.NewContext(false, tmproto.Header{})
    35  
    36  	suite.app = app
    37  	suite.sdkCtx = ctx
    38  	suite.addrs = simapp.AddTestAddrsIncremental(app, ctx, 4, sdk.NewInt(30000000))
    39  	suite.ctx = sdk.WrapSDKContext(ctx)
    40  	suite.keeper = suite.app.FeeGrantKeeper
    41  	suite.msgSrvr = keeper.NewMsgServerImpl(suite.keeper)
    42  	suite.atom = sdk.NewCoins(sdk.NewCoin("atom", sdk.NewInt(555)))
    43  }
    44  
    45  func (suite *KeeperTestSuite) TestKeeperCrud() {
    46  	// some helpers
    47  	eth := sdk.NewCoins(sdk.NewInt64Coin("eth", 123))
    48  	exp := suite.sdkCtx.BlockTime().AddDate(1, 0, 0)
    49  	basic := &feegrant.BasicAllowance{
    50  		SpendLimit: suite.atom,
    51  		Expiration: &exp,
    52  	}
    53  
    54  	basic2 := &feegrant.BasicAllowance{
    55  		SpendLimit: eth,
    56  		Expiration: &exp,
    57  	}
    58  
    59  	// let's set up some initial state here
    60  	err := suite.keeper.GrantAllowance(suite.sdkCtx, suite.addrs[0], suite.addrs[1], basic)
    61  	suite.Require().NoError(err)
    62  
    63  	err = suite.keeper.GrantAllowance(suite.sdkCtx, suite.addrs[0], suite.addrs[2], basic2)
    64  	suite.Require().NoError(err)
    65  
    66  	err = suite.keeper.GrantAllowance(suite.sdkCtx, suite.addrs[1], suite.addrs[2], basic)
    67  	suite.Require().NoError(err)
    68  
    69  	err = suite.keeper.GrantAllowance(suite.sdkCtx, suite.addrs[1], suite.addrs[3], basic)
    70  	suite.Require().NoError(err)
    71  
    72  	err = suite.keeper.GrantAllowance(suite.sdkCtx, suite.addrs[3], suite.addrs[0], basic2)
    73  	suite.Require().NoError(err)
    74  
    75  	// remove some, overwrite other
    76  	_, err = suite.msgSrvr.RevokeAllowance(suite.ctx, &feegrant.MsgRevokeAllowance{Granter: suite.addrs[0].String(), Grantee: suite.addrs[1].String()})
    77  	suite.Require().NoError(err)
    78  	_, err = suite.msgSrvr.RevokeAllowance(suite.ctx, &feegrant.MsgRevokeAllowance{Granter: suite.addrs[0].String(), Grantee: suite.addrs[2].String()})
    79  	suite.Require().NoError(err)
    80  
    81  	// revoke non-exist fee allowance
    82  	_, err = suite.msgSrvr.RevokeAllowance(suite.ctx, &feegrant.MsgRevokeAllowance{Granter: suite.addrs[0].String(), Grantee: suite.addrs[2].String()})
    83  	suite.Require().Error(err)
    84  
    85  	err = suite.keeper.GrantAllowance(suite.sdkCtx, suite.addrs[0], suite.addrs[2], basic)
    86  	suite.Require().NoError(err)
    87  
    88  	err = suite.keeper.GrantAllowance(suite.sdkCtx, suite.addrs[1], suite.addrs[2], basic2)
    89  	suite.Require().NoError(err)
    90  
    91  	// end state:
    92  	// addr -> addr3 (basic)
    93  	// addr2 -> addr3 (basic2), addr4(basic)
    94  	// addr4 -> addr (basic2)
    95  
    96  	// then lots of queries
    97  	cases := map[string]struct {
    98  		grantee   sdk.AccAddress
    99  		granter   sdk.AccAddress
   100  		allowance feegrant.FeeAllowanceI
   101  	}{
   102  		"addr revoked": {
   103  			granter: suite.addrs[0],
   104  			grantee: suite.addrs[1],
   105  		},
   106  		"addr revoked and added": {
   107  			granter:   suite.addrs[0],
   108  			grantee:   suite.addrs[2],
   109  			allowance: basic,
   110  		},
   111  		"addr never there": {
   112  			granter: suite.addrs[0],
   113  			grantee: suite.addrs[3],
   114  		},
   115  		"addr modified": {
   116  			granter:   suite.addrs[1],
   117  			grantee:   suite.addrs[2],
   118  			allowance: basic2,
   119  		},
   120  	}
   121  
   122  	for name, tc := range cases {
   123  		suite.Run(name, func() {
   124  			allow, _ := suite.keeper.GetAllowance(suite.sdkCtx, tc.granter, tc.grantee)
   125  
   126  			if tc.allowance == nil {
   127  				suite.Nil(allow)
   128  				return
   129  			}
   130  			suite.NotNil(allow)
   131  			suite.Equal(tc.allowance, allow)
   132  		})
   133  	}
   134  	accAddr, err := sdk.AccAddressFromBech32("link1k907plrxssuh2dxsd8k2jtp3de2t4xyhq6rkxd")
   135  	suite.Require().NoError(err)
   136  
   137  	// let's grant and revoke authorization to non existing account
   138  	err = suite.keeper.GrantAllowance(suite.sdkCtx, suite.addrs[3], accAddr, basic2)
   139  	suite.Require().NoError(err)
   140  
   141  	_, err = suite.keeper.GetAllowance(suite.sdkCtx, suite.addrs[3], accAddr)
   142  	suite.Require().NoError(err)
   143  
   144  	_, err = suite.msgSrvr.RevokeAllowance(suite.ctx, &feegrant.MsgRevokeAllowance{Granter: suite.addrs[3].String(), Grantee: accAddr.String()})
   145  	suite.Require().NoError(err)
   146  }
   147  
   148  func (suite *KeeperTestSuite) TestUseGrantedFee() {
   149  	eth := sdk.NewCoins(sdk.NewInt64Coin("eth", 123))
   150  	blockTime := suite.sdkCtx.BlockTime()
   151  	oneYear := blockTime.AddDate(1, 0, 0)
   152  
   153  	future := &feegrant.BasicAllowance{
   154  		SpendLimit: suite.atom,
   155  		Expiration: &oneYear,
   156  	}
   157  
   158  	// for testing limits of the contract
   159  	hugeAtom := sdk.NewCoins(sdk.NewInt64Coin("atom", 9999))
   160  	smallAtom := sdk.NewCoins(sdk.NewInt64Coin("atom", 1))
   161  	futureAfterSmall := &feegrant.BasicAllowance{
   162  		SpendLimit: sdk.NewCoins(sdk.NewInt64Coin("atom", 554)),
   163  		Expiration: &oneYear,
   164  	}
   165  
   166  	// then lots of queries
   167  	cases := map[string]struct {
   168  		grantee sdk.AccAddress
   169  		granter sdk.AccAddress
   170  		fee     sdk.Coins
   171  		allowed bool
   172  		final   feegrant.FeeAllowanceI
   173  	}{
   174  		"use entire pot": {
   175  			granter: suite.addrs[0],
   176  			grantee: suite.addrs[1],
   177  			fee:     suite.atom,
   178  			allowed: true,
   179  			final:   nil,
   180  		},
   181  		"too high": {
   182  			granter: suite.addrs[0],
   183  			grantee: suite.addrs[1],
   184  			fee:     hugeAtom,
   185  			allowed: false,
   186  			final:   future,
   187  		},
   188  		"use a little": {
   189  			granter: suite.addrs[0],
   190  			grantee: suite.addrs[1],
   191  			fee:     smallAtom,
   192  			allowed: true,
   193  			final:   futureAfterSmall,
   194  		},
   195  	}
   196  
   197  	for name, tc := range cases {
   198  		suite.Run(name, func() {
   199  			err := suite.keeper.GrantAllowance(suite.sdkCtx, suite.addrs[0], suite.addrs[1], future)
   200  			suite.Require().NoError(err)
   201  
   202  			err = suite.keeper.UseGrantedFees(suite.sdkCtx, tc.granter, tc.grantee, tc.fee, []sdk.Msg{})
   203  			if tc.allowed {
   204  				suite.NoError(err)
   205  			} else {
   206  				suite.Error(err)
   207  			}
   208  
   209  			loaded, _ := suite.keeper.GetAllowance(suite.sdkCtx, tc.granter, tc.grantee)
   210  			suite.Equal(tc.final, loaded)
   211  		})
   212  	}
   213  
   214  	expired := &feegrant.BasicAllowance{
   215  		SpendLimit: eth,
   216  		Expiration: &blockTime,
   217  	}
   218  	// creating expired feegrant
   219  	ctx := suite.sdkCtx.WithBlockTime(oneYear)
   220  	err := suite.keeper.GrantAllowance(ctx, suite.addrs[0], suite.addrs[2], expired)
   221  	suite.Require().NoError(err)
   222  
   223  	// expect error: feegrant expired
   224  	err = suite.keeper.UseGrantedFees(ctx, suite.addrs[0], suite.addrs[2], eth, []sdk.Msg{})
   225  	suite.Error(err)
   226  	suite.Contains(err.Error(), "fee allowance expired")
   227  
   228  	// verify: feegrant is revoked
   229  	_, err = suite.keeper.GetAllowance(ctx, suite.addrs[0], suite.addrs[2])
   230  	suite.Error(err)
   231  	suite.Contains(err.Error(), "fee-grant not found")
   232  }
   233  
   234  func (suite *KeeperTestSuite) TestIterateGrants() {
   235  	eth := sdk.NewCoins(sdk.NewInt64Coin("eth", 123))
   236  	exp := suite.sdkCtx.BlockTime().AddDate(1, 0, 0)
   237  
   238  	allowance := &feegrant.BasicAllowance{
   239  		SpendLimit: suite.atom,
   240  		Expiration: &exp,
   241  	}
   242  
   243  	allowance1 := &feegrant.BasicAllowance{
   244  		SpendLimit: eth,
   245  		Expiration: &exp,
   246  	}
   247  
   248  	err := suite.keeper.GrantAllowance(suite.sdkCtx, suite.addrs[0], suite.addrs[1], allowance)
   249  	suite.Require().NoError(err)
   250  	err = suite.keeper.GrantAllowance(suite.sdkCtx, suite.addrs[2], suite.addrs[1], allowance1)
   251  	suite.Require().NoError(err)
   252  
   253  	err = suite.keeper.IterateAllFeeAllowances(suite.sdkCtx, func(grant feegrant.Grant) bool {
   254  		suite.Require().Equal(suite.addrs[1].String(), grant.Grantee)
   255  		suite.Require().Contains([]string{suite.addrs[0].String(), suite.addrs[2].String()}, grant.Granter)
   256  		return true
   257  	})
   258  	suite.Require().NoError(err)
   259  }