github.com/Finschia/finschia-sdk@v0.48.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 tc := tc 124 suite.Run(name, func() { 125 allow, _ := suite.keeper.GetAllowance(suite.sdkCtx, tc.granter, tc.grantee) 126 127 if tc.allowance == nil { 128 suite.Nil(allow) 129 return 130 } 131 suite.NotNil(allow) 132 suite.Equal(tc.allowance, allow) 133 }) 134 } 135 accAddr, err := sdk.AccAddressFromBech32("link1k907plrxssuh2dxsd8k2jtp3de2t4xyhq6rkxd") 136 suite.Require().NoError(err) 137 138 // let's grant and revoke authorization to non existing account 139 err = suite.keeper.GrantAllowance(suite.sdkCtx, suite.addrs[3], accAddr, basic2) 140 suite.Require().NoError(err) 141 142 _, err = suite.keeper.GetAllowance(suite.sdkCtx, suite.addrs[3], accAddr) 143 suite.Require().NoError(err) 144 145 _, err = suite.msgSrvr.RevokeAllowance(suite.ctx, &feegrant.MsgRevokeAllowance{Granter: suite.addrs[3].String(), Grantee: accAddr.String()}) 146 suite.Require().NoError(err) 147 } 148 149 func (suite *KeeperTestSuite) TestUseGrantedFee() { 150 eth := sdk.NewCoins(sdk.NewInt64Coin("eth", 123)) 151 blockTime := suite.sdkCtx.BlockTime() 152 oneYear := blockTime.AddDate(1, 0, 0) 153 154 future := &feegrant.BasicAllowance{ 155 SpendLimit: suite.atom, 156 Expiration: &oneYear, 157 } 158 159 // for testing limits of the contract 160 hugeAtom := sdk.NewCoins(sdk.NewInt64Coin("atom", 9999)) 161 smallAtom := sdk.NewCoins(sdk.NewInt64Coin("atom", 1)) 162 futureAfterSmall := &feegrant.BasicAllowance{ 163 SpendLimit: sdk.NewCoins(sdk.NewInt64Coin("atom", 554)), 164 Expiration: &oneYear, 165 } 166 167 // then lots of queries 168 cases := map[string]struct { 169 grantee sdk.AccAddress 170 granter sdk.AccAddress 171 fee sdk.Coins 172 allowed bool 173 final feegrant.FeeAllowanceI 174 }{ 175 "use entire pot": { 176 granter: suite.addrs[0], 177 grantee: suite.addrs[1], 178 fee: suite.atom, 179 allowed: true, 180 final: nil, 181 }, 182 "too high": { 183 granter: suite.addrs[0], 184 grantee: suite.addrs[1], 185 fee: hugeAtom, 186 allowed: false, 187 final: future, 188 }, 189 "use a little": { 190 granter: suite.addrs[0], 191 grantee: suite.addrs[1], 192 fee: smallAtom, 193 allowed: true, 194 final: futureAfterSmall, 195 }, 196 } 197 198 for name, tc := range cases { 199 tc := tc 200 suite.Run(name, func() { 201 err := suite.keeper.GrantAllowance(suite.sdkCtx, suite.addrs[0], suite.addrs[1], future) 202 suite.Require().NoError(err) 203 204 err = suite.keeper.UseGrantedFees(suite.sdkCtx, tc.granter, tc.grantee, tc.fee, []sdk.Msg{}) 205 if tc.allowed { 206 suite.NoError(err) 207 } else { 208 suite.Error(err) 209 } 210 211 loaded, _ := suite.keeper.GetAllowance(suite.sdkCtx, tc.granter, tc.grantee) 212 suite.Equal(tc.final, loaded) 213 }) 214 } 215 216 expired := &feegrant.BasicAllowance{ 217 SpendLimit: eth, 218 Expiration: &blockTime, 219 } 220 // creating expired feegrant 221 ctx := suite.sdkCtx.WithBlockTime(oneYear) 222 err := suite.keeper.GrantAllowance(ctx, suite.addrs[0], suite.addrs[2], expired) 223 suite.Require().NoError(err) 224 225 // expect error: feegrant expired 226 err = suite.keeper.UseGrantedFees(ctx, suite.addrs[0], suite.addrs[2], eth, []sdk.Msg{}) 227 suite.Error(err) 228 suite.Contains(err.Error(), "fee allowance expired") 229 230 // verify: feegrant is revoked 231 _, err = suite.keeper.GetAllowance(ctx, suite.addrs[0], suite.addrs[2]) 232 suite.Error(err) 233 suite.Contains(err.Error(), "fee-grant not found") 234 } 235 236 func (suite *KeeperTestSuite) TestIterateGrants() { 237 eth := sdk.NewCoins(sdk.NewInt64Coin("eth", 123)) 238 exp := suite.sdkCtx.BlockTime().AddDate(1, 0, 0) 239 240 allowance := &feegrant.BasicAllowance{ 241 SpendLimit: suite.atom, 242 Expiration: &exp, 243 } 244 245 allowance1 := &feegrant.BasicAllowance{ 246 SpendLimit: eth, 247 Expiration: &exp, 248 } 249 250 suite.keeper.GrantAllowance(suite.sdkCtx, suite.addrs[0], suite.addrs[1], allowance) 251 suite.keeper.GrantAllowance(suite.sdkCtx, suite.addrs[2], suite.addrs[1], allowance1) 252 253 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 }