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 }