From eb6e701b8a7ef1d19dc3536daa6070ad642aee3b Mon Sep 17 00:00:00 2001 From: Cian Hatton Date: Tue, 10 Jan 2023 15:14:16 +0000 Subject: [PATCH 1/8] test: adding happy path test for transfer authz --- e2e/testconfig/testconfig.go | 8 +++ e2e/tests/transfer/authz_test.go | 119 +++++++++++++++++++++++++++++++ e2e/testsuite/codec.go | 4 ++ e2e/testsuite/testsuite.go | 14 +++- 4 files changed, 144 insertions(+), 1 deletion(-) create mode 100644 e2e/tests/transfer/authz_test.go diff --git a/e2e/testconfig/testconfig.go b/e2e/testconfig/testconfig.go index d4cb5eab329..84451f109ab 100644 --- a/e2e/testconfig/testconfig.go +++ b/e2e/testconfig/testconfig.go @@ -4,6 +4,7 @@ import ( "encoding/json" "fmt" "os" + "strings" "github.com/cosmos/cosmos-sdk/codec" simappparams "github.com/cosmos/cosmos-sdk/simapp/params" @@ -129,6 +130,13 @@ func GetChainBTag() string { return chainBTag } +// IsCI returns true if the tests are running in CI, false is returned +// if the tests are running locally. +// Note: github actions passes a CI env value of true by default to all runners. +func IsCI() bool { + return strings.ToLower(os.Getenv("CI")) == "true" +} + // ChainOptions stores chain configurations for the chains that will be // created for the tests. They can be modified by passing ChainOptionConfiguration // to E2ETestSuite.GetChains. diff --git a/e2e/tests/transfer/authz_test.go b/e2e/tests/transfer/authz_test.go new file mode 100644 index 00000000000..715150fc673 --- /dev/null +++ b/e2e/tests/transfer/authz_test.go @@ -0,0 +1,119 @@ +package transfer + +import ( + "context" + "testing" + + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/authz" + test "github.com/strangelove-ventures/ibctest/v6/testutil" + "github.com/stretchr/testify/suite" + + "github.com/cosmos/ibc-go/e2e/testsuite" + "github.com/cosmos/ibc-go/e2e/testvalues" + transfertypes "github.com/cosmos/ibc-go/v6/modules/apps/transfer/types" +) + +func TestAuthzTransferTestSuite(t *testing.T) { + suite.Run(t, new(AuthzTransferTestSuite)) +} + +type AuthzTransferTestSuite struct { + testsuite.E2ETestSuite +} + +func (suite *AuthzTransferTestSuite) TestAuthz_MsgTransfer_Succeeds() { + t := suite.T() + ctx := context.TODO() + + relayer, channelA := suite.SetupChainsRelayerAndChannel(ctx, transferChannelOptions()) + chainA, chainB := suite.GetChains() + + chainADenom := chainA.Config().Denom + + granterWallet := suite.CreateUserOnChainA(ctx, testvalues.StartingTokenAmount) + granterAddress := granterWallet.Bech32Address(chainA.Config().Bech32Prefix) + + granteeWallet := suite.CreateUserOnChainA(ctx, testvalues.StartingTokenAmount) + granteeAddress := granteeWallet.Bech32Address(chainA.Config().Bech32Prefix) + + chainBWallet := suite.CreateUserOnChainB(ctx, testvalues.StartingTokenAmount) + chainBAddress := chainBWallet.Bech32Address(chainB.Config().Bech32Prefix) + + t.Run("start relayer", func(t *testing.T) { + suite.StartRelayer(relayer) + }) + + t.Run("broadcast MsgGrant", func(t *testing.T) { + transferAuth := transfertypes.TransferAuthorization{ + Allocations: []transfertypes.PortChannelAmount{ + { + SourcePort: channelA.PortID, + SourceChannel: channelA.ChannelID, + SpendLimit: sdk.NewCoins(sdk.NewCoin(chainADenom, sdk.NewInt(testvalues.StartingTokenAmount))), + AllowedAddresses: []string{chainBAddress}, + }, + }, + } + + authAny, err := codectypes.NewAnyWithValue(&transferAuth) + suite.Require().NoError(err) + + msgGrant := &authz.MsgGrant{ + Granter: granterAddress, + Grantee: granteeAddress, + Grant: authz.Grant{ + Authorization: authAny, + // no expiration + Expiration: nil, + }, + } + + resp, err := suite.BroadcastMessages(context.TODO(), chainA, granterWallet, msgGrant) + suite.AssertValidTxResponse(resp) + suite.Require().NoError(err) + }) + + t.Run("broadcast MsgExec", func(t *testing.T) { + transferMsg := transfertypes.MsgTransfer{ + SourcePort: channelA.PortID, + SourceChannel: channelA.ChannelID, + Token: testvalues.DefaultTransferAmount(chainADenom), + Sender: granterAddress, + Receiver: chainBAddress, + TimeoutHeight: suite.GetTimeoutHeight(ctx, chainB), + } + + transferAny, err := codectypes.NewAnyWithValue(&transferMsg) + suite.Require().NoError(err) + + msgExec := &authz.MsgExec{ + Grantee: granteeAddress, + Msgs: []*codectypes.Any{transferAny}, + } + + resp, err := suite.BroadcastMessages(context.TODO(), chainA, granteeWallet, msgExec) + suite.AssertValidTxResponse(resp) + suite.Require().NoError(err) + }) + + t.Run("verify granter wallet amount", func(t *testing.T) { + actualBalance, err := suite.GetChainANativeBalance(ctx, granterWallet) + suite.Require().NoError(err) + + expected := testvalues.StartingTokenAmount - testvalues.IBCTransferAmount + suite.Require().Equal(expected, actualBalance) + }) + + suite.Require().NoError(test.WaitForBlocks(context.TODO(), 10, chainB)) + + t.Run("verify receiver wallet amount", func(t *testing.T) { + chainBIBCToken := testsuite.GetIBCToken(chainADenom, channelA.Counterparty.PortID, channelA.Counterparty.ChannelID) + actualBalance, err := chainB.GetBalance(ctx, chainBAddress, chainBIBCToken.IBCDenom()) + suite.Require().NoError(err) + suite.Require().Equal(testvalues.IBCTransferAmount, actualBalance) + }) + + // TODO: query and make sure spend limit is reduced +} diff --git a/e2e/testsuite/codec.go b/e2e/testsuite/codec.go index dcee96ced4f..4181ef2ff0f 100644 --- a/e2e/testsuite/codec.go +++ b/e2e/testsuite/codec.go @@ -3,9 +3,11 @@ package testsuite import ( "github.com/cosmos/cosmos-sdk/codec" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + "github.com/cosmos/cosmos-sdk/x/authz" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" govv1beta1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1" + transfertypes "github.com/cosmos/ibc-go/v6/modules/apps/transfer/types" simappparams "github.com/cosmos/ibc-go/v6/testing/simapp/params" ) @@ -24,6 +26,8 @@ func codecAndEncodingConfig() (*codec.ProtoCodec, simappparams.EncodingConfig) { banktypes.RegisterInterfaces(cfg.InterfaceRegistry) govv1beta1.RegisterInterfaces(cfg.InterfaceRegistry) authtypes.RegisterInterfaces(cfg.InterfaceRegistry) + authz.RegisterInterfaces(cfg.InterfaceRegistry) + transfertypes.RegisterInterfaces(cfg.InterfaceRegistry) cdc := codec.NewProtoCodec(cfg.InterfaceRegistry) return cdc, cfg } diff --git a/e2e/testsuite/testsuite.go b/e2e/testsuite/testsuite.go index b8c03f0e5f8..f028c8b7fac 100644 --- a/e2e/testsuite/testsuite.go +++ b/e2e/testsuite/testsuite.go @@ -11,6 +11,7 @@ import ( "github.com/cosmos/cosmos-sdk/client/tx" sdk "github.com/cosmos/cosmos-sdk/types" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + "github.com/cosmos/cosmos-sdk/x/authz" govtypesv1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1" govtypesv1beta1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1" grouptypes "github.com/cosmos/cosmos-sdk/x/group" @@ -81,6 +82,7 @@ type GRPCClients struct { GroupsQueryClient grouptypes.QueryClient ParamsQueryClient paramsproposaltypes.QueryClient AuthQueryClient authtypes.QueryClient + AuthZQueryClient authz.QueryClient } // path is a pairing of two chains which will be used in a test. @@ -425,7 +427,7 @@ func (s *E2ETestSuite) createCosmosChains(chainOptions testconfig.ChainOptions) logger := zaptest.NewLogger(s.T()) - numValidators, numFullNodes := 4, 1 + numValidators, numFullNodes := getValidatorsAndFullNodes() chainA := cosmos.NewCosmosChain(s.T().Name(), *chainOptions.ChainAConfig, numValidators, numFullNodes, logger) chainB := cosmos.NewCosmosChain(s.T().Name(), *chainOptions.ChainBConfig, numValidators, numFullNodes, logger) @@ -543,3 +545,13 @@ func (s *E2ETestSuite) QueryModuleAccountAddress(ctx context.Context, moduleName func GetIBCToken(fullTokenDenom string, portID, channelID string) transfertypes.DenomTrace { return transfertypes.ParseDenomTrace(fmt.Sprintf("%s/%s/%s", portID, channelID, fullTokenDenom)) } + +// getValidatorsAndFullNodes returns the number of validators and full nodes respectively that should be used for +// the test. If the test is running in CI, more nodes are used, when running locally a single node is used to +// use less resources and allow the tests to run faster. +func getValidatorsAndFullNodes() (int, int) { + if testconfig.IsCI() { + return 4, 1 + } + return 1, 0 +} From d2c8a6feee7e9d7cbe594f5b3c4ca7e54b157ea9 Mon Sep 17 00:00:00 2001 From: Cian Hatton Date: Wed, 11 Jan 2023 09:39:36 +0000 Subject: [PATCH 2/8] wip: adding assertion on grants --- e2e/tests/transfer/authz_test.go | 17 ++++++++++++++++- e2e/testsuite/testsuite.go | 18 +++++++++++++++++- 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/e2e/tests/transfer/authz_test.go b/e2e/tests/transfer/authz_test.go index 715150fc673..7a797925bfb 100644 --- a/e2e/tests/transfer/authz_test.go +++ b/e2e/tests/transfer/authz_test.go @@ -115,5 +115,20 @@ func (suite *AuthzTransferTestSuite) TestAuthz_MsgTransfer_Succeeds() { suite.Require().Equal(testvalues.IBCTransferAmount, actualBalance) }) - // TODO: query and make sure spend limit is reduced + suite.Require().NoError(test.WaitForBlocks(context.TODO(), 10, chainA, chainB)) + + t.Run("verify granter grants", func(t *testing.T) { + grants, err := suite.QueryGranterGrants(ctx, chainA, granterAddress) + + suite.Require().NoError(err) + suite.Require().Len(grants, 1) + grant := grants[0] + t.Logf("%+v", grant) + t.Logf("%+v", grant.Authorization.GetCachedValue()) + //transferAuth, ok := grant.Authorization.GetCachedValue().(*transfertypes.TransferAuthorization) + //suite.Require().True(ok) + + //expectedSpendLimit := sdk.NewCoins(sdk.NewCoin(chainADenom, sdk.NewInt(testvalues.StartingTokenAmount-testvalues.IBCTransferAmount))) + //suite.Require().Equal(expectedSpendLimit, transferAuth.Allocations[0].SpendLimit) + }) } diff --git a/e2e/testsuite/testsuite.go b/e2e/testsuite/testsuite.go index f028c8b7fac..145df1648ff 100644 --- a/e2e/testsuite/testsuite.go +++ b/e2e/testsuite/testsuite.go @@ -82,7 +82,7 @@ type GRPCClients struct { GroupsQueryClient grouptypes.QueryClient ParamsQueryClient paramsproposaltypes.QueryClient AuthQueryClient authtypes.QueryClient - AuthZQueryClient authz.QueryClient + AuthZQueryClient authz.QueryClient } // path is a pairing of two chains which will be used in a test. @@ -393,6 +393,7 @@ func (s *E2ETestSuite) InitGRPCClients(chain *cosmos.CosmosChain) { GroupsQueryClient: grouptypes.NewQueryClient(grpcConn), ParamsQueryClient: paramsproposaltypes.NewQueryClient(grpcConn), AuthQueryClient: authtypes.NewQueryClient(grpcConn), + AuthZQueryClient: authz.NewQueryClient(grpcConn), } } @@ -541,6 +542,21 @@ func (s *E2ETestSuite) QueryModuleAccountAddress(ctx context.Context, moduleName return moduleAccount.GetAddress(), nil } +// QueryGranterGrants returns granter grants +func (s *E2ETestSuite) QueryGranterGrants(ctx context.Context, chain *cosmos.CosmosChain, granterAddress string) ([]*authz.GrantAuthorization, error) { + authzClient := s.GetChainGRCPClients(chain).AuthZQueryClient + queryRequest := &authz.QueryGranterGrantsRequest{ + Granter: granterAddress, + } + + grants, err := authzClient.GranterGrants(ctx, queryRequest) + if err != nil { + return nil, err + } + + return grants.Grants, nil +} + // GetIBCToken returns the denomination of the full token denom sent to the receiving channel func GetIBCToken(fullTokenDenom string, portID, channelID string) transfertypes.DenomTrace { return transfertypes.ParseDenomTrace(fmt.Sprintf("%s/%s/%s", portID, channelID, fullTokenDenom)) From a97c4b81f54a22a245b7f57e7baa93fb4667fec3 Mon Sep 17 00:00:00 2001 From: Cian Hatton Date: Wed, 11 Jan 2023 10:19:46 +0000 Subject: [PATCH 3/8] chore: assert grant authorization after msg transfer succeeds --- e2e/tests/transfer/authz_test.go | 46 +++++++++++++++++++------------- 1 file changed, 27 insertions(+), 19 deletions(-) diff --git a/e2e/tests/transfer/authz_test.go b/e2e/tests/transfer/authz_test.go index 7a797925bfb..25f7ed7113a 100644 --- a/e2e/tests/transfer/authz_test.go +++ b/e2e/tests/transfer/authz_test.go @@ -38,8 +38,8 @@ func (suite *AuthzTransferTestSuite) TestAuthz_MsgTransfer_Succeeds() { granteeWallet := suite.CreateUserOnChainA(ctx, testvalues.StartingTokenAmount) granteeAddress := granteeWallet.Bech32Address(chainA.Config().Bech32Prefix) - chainBWallet := suite.CreateUserOnChainB(ctx, testvalues.StartingTokenAmount) - chainBAddress := chainBWallet.Bech32Address(chainB.Config().Bech32Prefix) + receiverWallet := suite.CreateUserOnChainB(ctx, testvalues.StartingTokenAmount) + receiverWalletAddress := receiverWallet.Bech32Address(chainB.Config().Bech32Prefix) t.Run("start relayer", func(t *testing.T) { suite.StartRelayer(relayer) @@ -52,7 +52,7 @@ func (suite *AuthzTransferTestSuite) TestAuthz_MsgTransfer_Succeeds() { SourcePort: channelA.PortID, SourceChannel: channelA.ChannelID, SpendLimit: sdk.NewCoins(sdk.NewCoin(chainADenom, sdk.NewInt(testvalues.StartingTokenAmount))), - AllowedAddresses: []string{chainBAddress}, + AllowedAddresses: []string{receiverWalletAddress}, }, }, } @@ -75,13 +75,13 @@ func (suite *AuthzTransferTestSuite) TestAuthz_MsgTransfer_Succeeds() { suite.Require().NoError(err) }) - t.Run("broadcast MsgExec", func(t *testing.T) { + t.Run("exec MsgTransfer", func(t *testing.T) { transferMsg := transfertypes.MsgTransfer{ SourcePort: channelA.PortID, SourceChannel: channelA.ChannelID, Token: testvalues.DefaultTransferAmount(chainADenom), Sender: granterAddress, - Receiver: chainBAddress, + Receiver: receiverWalletAddress, TimeoutHeight: suite.GetTimeoutHeight(ctx, chainB), } @@ -110,25 +110,33 @@ func (suite *AuthzTransferTestSuite) TestAuthz_MsgTransfer_Succeeds() { t.Run("verify receiver wallet amount", func(t *testing.T) { chainBIBCToken := testsuite.GetIBCToken(chainADenom, channelA.Counterparty.PortID, channelA.Counterparty.ChannelID) - actualBalance, err := chainB.GetBalance(ctx, chainBAddress, chainBIBCToken.IBCDenom()) + actualBalance, err := chainB.GetBalance(ctx, receiverWalletAddress, chainBIBCToken.IBCDenom()) suite.Require().NoError(err) suite.Require().Equal(testvalues.IBCTransferAmount, actualBalance) }) - suite.Require().NoError(test.WaitForBlocks(context.TODO(), 10, chainA, chainB)) - - t.Run("verify granter grants", func(t *testing.T) { - grants, err := suite.QueryGranterGrants(ctx, chainA, granterAddress) + t.Run("granter grant spend limit reduced", func(t *testing.T) { + grantAuths, err := suite.QueryGranterGrants(ctx, chainA, granterAddress) suite.Require().NoError(err) - suite.Require().Len(grants, 1) - grant := grants[0] - t.Logf("%+v", grant) - t.Logf("%+v", grant.Authorization.GetCachedValue()) - //transferAuth, ok := grant.Authorization.GetCachedValue().(*transfertypes.TransferAuthorization) - //suite.Require().True(ok) - - //expectedSpendLimit := sdk.NewCoins(sdk.NewCoin(chainADenom, sdk.NewInt(testvalues.StartingTokenAmount-testvalues.IBCTransferAmount))) - //suite.Require().Equal(expectedSpendLimit, transferAuth.Allocations[0].SpendLimit) + suite.Require().Len(grantAuths, 1) + grantAuthorization := grantAuths[0] + + transferAuth := suite.extractTransferAuthorizationFromGrantAuthorization(grantAuthorization) + expectedSpendLimit := sdk.NewCoins(sdk.NewCoin(chainADenom, sdk.NewInt(testvalues.StartingTokenAmount-testvalues.IBCTransferAmount))) + suite.Require().Equal(expectedSpendLimit, transferAuth.Allocations[0].SpendLimit) }) } + +// extractTransferAuthorizationFromGrantAuthorization extracts a TransferAuthorization from the given +// GrantAuthorization. +func (suite *AuthzTransferTestSuite) extractTransferAuthorizationFromGrantAuthorization(grantAuth *authz.GrantAuthorization) *transfertypes.TransferAuthorization { + cfg := testsuite.EncodingConfig() + var authorization authz.Authorization + err := cfg.InterfaceRegistry.UnpackAny(grantAuth.Authorization, &authorization) + suite.Require().NoError(err) + + transferAuth, ok := authorization.(*transfertypes.TransferAuthorization) + suite.Require().True(ok) + return transferAuth +} From 84847f1bdb02b0960f7fd7884e63ad5ff029d385 Mon Sep 17 00:00:00 2001 From: Cian Hatton Date: Wed, 11 Jan 2023 10:22:50 +0000 Subject: [PATCH 4/8] chore: updated docstring --- e2e/testsuite/testsuite.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/e2e/testsuite/testsuite.go b/e2e/testsuite/testsuite.go index 145df1648ff..c2fb576d442 100644 --- a/e2e/testsuite/testsuite.go +++ b/e2e/testsuite/testsuite.go @@ -542,7 +542,7 @@ func (s *E2ETestSuite) QueryModuleAccountAddress(ctx context.Context, moduleName return moduleAccount.GetAddress(), nil } -// QueryGranterGrants returns granter grants +// QueryGranterGrants returns all GrantAuthorizations for the given granterAddress. func (s *E2ETestSuite) QueryGranterGrants(ctx context.Context, chain *cosmos.CosmosChain, granterAddress string) ([]*authz.GrantAuthorization, error) { authzClient := s.GetChainGRCPClients(chain).AuthZQueryClient queryRequest := &authz.QueryGranterGrantsRequest{ From a0b4ad047a759d57cf719209a1165acf96eb3914 Mon Sep 17 00:00:00 2001 From: Cian Hatton Date: Wed, 11 Jan 2023 10:25:13 +0000 Subject: [PATCH 5/8] chore: added TestAuthzTransferTestSuite to github workflow --- .github/workflows/e2e-manual-simd.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/e2e-manual-simd.yaml b/.github/workflows/e2e-manual-simd.yaml index 76bf85c6e2d..58d3fd0f3c6 100644 --- a/.github/workflows/e2e-manual-simd.yaml +++ b/.github/workflows/e2e-manual-simd.yaml @@ -17,6 +17,7 @@ on: - TestInterchainAccountsGroupsTestSuite - TestInterchainAccountsGovTestSuite - TestIncentivizedInterchainAccountsTestSuite + - TestAuthzTransferTestSuite chain-image: description: 'The image to use for chain A' required: true From 4eb6f417c278e607e94e582ce62a6e8d4cd60529 Mon Sep 17 00:00:00 2001 From: Cian Hatton Date: Wed, 11 Jan 2023 10:38:44 +0000 Subject: [PATCH 6/8] chore: rename PortChannelAmount to Allocation --- e2e/tests/transfer/authz_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/e2e/tests/transfer/authz_test.go b/e2e/tests/transfer/authz_test.go index 25f7ed7113a..73e99f86941 100644 --- a/e2e/tests/transfer/authz_test.go +++ b/e2e/tests/transfer/authz_test.go @@ -47,12 +47,12 @@ func (suite *AuthzTransferTestSuite) TestAuthz_MsgTransfer_Succeeds() { t.Run("broadcast MsgGrant", func(t *testing.T) { transferAuth := transfertypes.TransferAuthorization{ - Allocations: []transfertypes.PortChannelAmount{ + Allocations: []transfertypes.Allocation{ { SourcePort: channelA.PortID, SourceChannel: channelA.ChannelID, SpendLimit: sdk.NewCoins(sdk.NewCoin(chainADenom, sdk.NewInt(testvalues.StartingTokenAmount))), - AllowedAddresses: []string{receiverWalletAddress}, + AllowList: []string{receiverWalletAddress}, }, }, } From 3870686d729e17b5b09fe35d2624aacd094d7625 Mon Sep 17 00:00:00 2001 From: Cian Hatton Date: Wed, 11 Jan 2023 15:30:35 +0000 Subject: [PATCH 7/8] chore: addressing PR feedback --- e2e/tests/transfer/authz_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/e2e/tests/transfer/authz_test.go b/e2e/tests/transfer/authz_test.go index 73e99f86941..40492e5b0f0 100644 --- a/e2e/tests/transfer/authz_test.go +++ b/e2e/tests/transfer/authz_test.go @@ -75,7 +75,7 @@ func (suite *AuthzTransferTestSuite) TestAuthz_MsgTransfer_Succeeds() { suite.Require().NoError(err) }) - t.Run("exec MsgTransfer", func(t *testing.T) { + t.Run("broadcast MsgExec for ibc MsgTransfer", func(t *testing.T) { transferMsg := transfertypes.MsgTransfer{ SourcePort: channelA.PortID, SourceChannel: channelA.ChannelID, From 97f809c938c661f0a218e90542586eb08f6303f5 Mon Sep 17 00:00:00 2001 From: Cian Hatton Date: Wed, 11 Jan 2023 16:47:14 +0000 Subject: [PATCH 8/8] chore: addressing PR feedback --- e2e/tests/transfer/authz_test.go | 44 +++++++++++++++++++++----------- 1 file changed, 29 insertions(+), 15 deletions(-) diff --git a/e2e/tests/transfer/authz_test.go b/e2e/tests/transfer/authz_test.go index 40492e5b0f0..4da10d7d523 100644 --- a/e2e/tests/transfer/authz_test.go +++ b/e2e/tests/transfer/authz_test.go @@ -45,14 +45,15 @@ func (suite *AuthzTransferTestSuite) TestAuthz_MsgTransfer_Succeeds() { suite.StartRelayer(relayer) }) - t.Run("broadcast MsgGrant", func(t *testing.T) { + // createMsgGrantFn initializes a TransferAuthorization and broadcasts a MsgGrant message. + createMsgGrantFn := func(t *testing.T) { transferAuth := transfertypes.TransferAuthorization{ Allocations: []transfertypes.Allocation{ { - SourcePort: channelA.PortID, - SourceChannel: channelA.ChannelID, - SpendLimit: sdk.NewCoins(sdk.NewCoin(chainADenom, sdk.NewInt(testvalues.StartingTokenAmount))), - AllowList: []string{receiverWalletAddress}, + SourcePort: channelA.PortID, + SourceChannel: channelA.ChannelID, + SpendLimit: sdk.NewCoins(sdk.NewCoin(chainADenom, sdk.NewInt(testvalues.StartingTokenAmount))), + AllowList: []string{receiverWalletAddress}, }, }, } @@ -73,7 +74,25 @@ func (suite *AuthzTransferTestSuite) TestAuthz_MsgTransfer_Succeeds() { resp, err := suite.BroadcastMessages(context.TODO(), chainA, granterWallet, msgGrant) suite.AssertValidTxResponse(resp) suite.Require().NoError(err) - }) + } + + // verifyGrantFn returns a test function which asserts chainA has a grant authorization + // with the given spend limit. + verifyGrantFn := func(expectedLimit int64) func(t *testing.T) { + return func(t *testing.T) { + grantAuths, err := suite.QueryGranterGrants(ctx, chainA, granterAddress) + + suite.Require().NoError(err) + suite.Require().Len(grantAuths, 1) + grantAuthorization := grantAuths[0] + + transferAuth := suite.extractTransferAuthorizationFromGrantAuthorization(grantAuthorization) + expectedSpendLimit := sdk.NewCoins(sdk.NewCoin(chainADenom, sdk.NewInt(expectedLimit))) + suite.Require().Equal(expectedSpendLimit, transferAuth.Allocations[0].SpendLimit) + } + } + + t.Run("broadcast MsgGrant", createMsgGrantFn) t.Run("broadcast MsgExec for ibc MsgTransfer", func(t *testing.T) { transferMsg := transfertypes.MsgTransfer{ @@ -115,17 +134,12 @@ func (suite *AuthzTransferTestSuite) TestAuthz_MsgTransfer_Succeeds() { suite.Require().Equal(testvalues.IBCTransferAmount, actualBalance) }) - t.Run("granter grant spend limit reduced", func(t *testing.T) { - grantAuths, err := suite.QueryGranterGrants(ctx, chainA, granterAddress) + t.Run("granter grant spend limit reduced", verifyGrantFn(testvalues.StartingTokenAmount-testvalues.IBCTransferAmount)) - suite.Require().NoError(err) - suite.Require().Len(grantAuths, 1) - grantAuthorization := grantAuths[0] + t.Run("re-initialize MsgGrant", createMsgGrantFn) + + t.Run("granter grant was reinitialized", verifyGrantFn(testvalues.StartingTokenAmount)) - transferAuth := suite.extractTransferAuthorizationFromGrantAuthorization(grantAuthorization) - expectedSpendLimit := sdk.NewCoins(sdk.NewCoin(chainADenom, sdk.NewInt(testvalues.StartingTokenAmount-testvalues.IBCTransferAmount))) - suite.Require().Equal(expectedSpendLimit, transferAuth.Allocations[0].SpendLimit) - }) } // extractTransferAuthorizationFromGrantAuthorization extracts a TransferAuthorization from the given