From d83bbbb86a4bd6fe5ab20320a0631f4c345026da Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Thu, 2 Feb 2023 10:46:32 +0100 Subject: [PATCH 1/5] feat: Added authz support for ics20 (#3079) Co-authored-by: Damian Nolan Co-authored-by: Cian Hatton Co-authored-by: Charleen Fei Co-authored-by: Zaki Manian (cherry picked from commit 6c008ea25d72c672949794dc4dba73a530d46391) # Conflicts: # .github/workflows/e2e-manual-simd.yaml # e2e/testconfig/testconfig.go # e2e/testsuite/codec.go # e2e/testsuite/testsuite.go # e2e/testvalues/values.go # go.mod # modules/apps/transfer/types/codec.go # modules/apps/transfer/types/types_test.go --- .github/workflows/e2e-manual-simd.yaml | 85 +++ docs/ibc/proto-docs.md | 54 ++ e2e/testconfig/testconfig.go | 295 ++++++++ e2e/tests/transfer/authz_test.go | 329 +++++++++ e2e/testsuite/codec.go | 48 ++ e2e/testsuite/testsuite.go | 575 +++++++++++++++ e2e/testvalues/values.go | 45 ++ go.mod | 13 + modules/apps/transfer/types/ack_test.go | 29 - modules/apps/transfer/types/authz.pb.go | 695 ++++++++++++++++++ modules/apps/transfer/types/codec.go | 12 + modules/apps/transfer/types/errors.go | 1 + .../transfer/types/transfer_authorization.go | 127 ++++ .../types/transfer_authorization_test.go | 282 +++++++ modules/apps/transfer/types/types_test.go | 44 ++ .../ibc/applications/transfer/v1/authz.proto | 31 + 16 files changed, 2636 insertions(+), 29 deletions(-) create mode 100644 .github/workflows/e2e-manual-simd.yaml create mode 100644 e2e/testconfig/testconfig.go create mode 100644 e2e/tests/transfer/authz_test.go create mode 100644 e2e/testsuite/codec.go create mode 100644 e2e/testsuite/testsuite.go create mode 100644 e2e/testvalues/values.go delete mode 100644 modules/apps/transfer/types/ack_test.go create mode 100644 modules/apps/transfer/types/authz.pb.go create mode 100644 modules/apps/transfer/types/transfer_authorization.go create mode 100644 modules/apps/transfer/types/transfer_authorization_test.go create mode 100644 modules/apps/transfer/types/types_test.go create mode 100644 proto/ibc/applications/transfer/v1/authz.proto diff --git a/.github/workflows/e2e-manual-simd.yaml b/.github/workflows/e2e-manual-simd.yaml new file mode 100644 index 00000000000..611ad78e9c6 --- /dev/null +++ b/.github/workflows/e2e-manual-simd.yaml @@ -0,0 +1,85 @@ +name: Manual E2E (Simd) +on: + # when https://github.com/community/community/discussions/11795 is resolved + # we will be able to dynamically build up the list of valid inputs. + # for now this needs to be manual. + workflow_dispatch: + inputs: + test-entry-point: + description: 'Test entry point' + required: true + type: choice + options: + - TestTransferTestSuite + - TestIncentivizedTransferTestSuite + - TestConnectionTestSuite + - TestInterchainAccountsTestSuite + - TestInterchainAccountsGroupsTestSuite + - TestInterchainAccountsGovTestSuite + - TestIncentivizedInterchainAccountsTestSuite + - TestAuthzTransferTestSuite + chain-image: + description: 'The image to use for chain A' + required: true + type: string + default: "ghcr.io/cosmos/ibc-go-simd" + chain-binary: + description: 'Specify the chain binary to be used' + required: true + type: string + default: "simd" + chain-a-tag: + description: 'The tag to use for chain A' + required: true + type: choice + default: main + options: + - main + - v6.1.0 + - v5.2.0 + - v4.2.0 + - v4.1.1 + - v3.4.0 + - v3.3.1 + - v2.5.0 + - v2.4.2 + chain-a-tag-override: + description: 'Specify an arbitrary tag for chain A' + required: false + type: string + chain-b-tag: + default: v6.0.0 + description: 'The tag to use for chain B' + required: true + type: choice + options: + - main + - v6.1.0 + - v5.2.0 + - v4.2.0 + - v4.1.1 + - v3.4.0 + - v3.3.1 + - v2.5.0 + - v2.4.2 + chain-b-tag-override: + description: 'Specify an arbitrary tag for chain B' + required: false + type: string + relayer-tag: + description: 'The tag to use for the relayer' + required: true + default: "v2.1.2" + type: string + + +jobs: + e2e-manual: + uses: ./.github/workflows/e2e-test-workflow-call.yml + with: + chain-image: "${{ github.event.inputs.chain-image }}" + chain-a-tag: "${{ github.event.inputs.chain-a-tag-override || github.event.inputs.chain-a-tag }}" + chain-b-tag: "${{ github.event.inputs.chain-b-tag-override || github.event.inputs.chain-b-tag }}" + relayer-tag: "${{ github.event.inputs.relayer-tag }}" + test-entry-point: "${{ github.event.inputs.test-entry-point }}" + chain-binary: "${{ github.event.inputs.chain-binary }}" diff --git a/docs/ibc/proto-docs.md b/docs/ibc/proto-docs.md index 052be9fff4e..31ea7dfe6a9 100644 --- a/docs/ibc/proto-docs.md +++ b/docs/ibc/proto-docs.md @@ -154,6 +154,10 @@ - [Msg](#ibc.applications.transfer.v1.Msg) +- [ibc/applications/transfer/v2/authz.proto](#ibc/applications/transfer/v2/authz.proto) + - [PortChannelAmount](#ibc.applications.transfer.v2.PortChannelAmount) + - [TransferAuthorization](#ibc.applications.transfer.v2.TransferAuthorization) + - [ibc/applications/transfer/v2/packet.proto](#ibc/applications/transfer/v2/packet.proto) - [FungibleTokenPacketData](#ibc.applications.transfer.v2.FungibleTokenPacketData) @@ -2291,6 +2295,56 @@ Msg defines the ibc/transfer Msg service. + +

Top

+ +## ibc/applications/transfer/v2/authz.proto + + + + + +### PortChannelAmount + + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `source_port` | [string](#string) | | the port on which the packet will be sent | +| `source_channel` | [string](#string) | | the channel by which the packet will be sent | +| `spend_limit` | [cosmos.base.v1beta1.Coin](#cosmos.base.v1beta1.Coin) | repeated | spend limitation on the channel | +| `allowed_addresses` | [string](#string) | repeated | | + + + + + + + + +### TransferAuthorization +TransferAuthorization allows the grantee to spend up to spend_limit coins from +the granter's account for ibc transfer on a specific channel + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `allocations` | [PortChannelAmount](#ibc.applications.transfer.v2.PortChannelAmount) | repeated | port and channel amounts | + + + + + + + + + + + + + + +

Top

diff --git a/e2e/testconfig/testconfig.go b/e2e/testconfig/testconfig.go new file mode 100644 index 00000000000..fcd7e262caf --- /dev/null +++ b/e2e/testconfig/testconfig.go @@ -0,0 +1,295 @@ +package testconfig + +import ( + "encoding/json" + "fmt" + "os" + "strings" + + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/module/testutil" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + govv1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1" + govv1beta1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1" + gogoproto "github.com/cosmos/gogoproto/proto" + "github.com/strangelove-ventures/interchaintest/v7/ibc" + + "github.com/cosmos/ibc-go/e2e/semverutil" + "github.com/cosmos/ibc-go/e2e/testvalues" +) + +const ( + // ChainImageEnv specifies the image that the chains will use. If left unspecified, it will + // default to being determined based on the specified binary. E.g. ghcr.io/cosmos/ibc-go-simd + ChainImageEnv = "CHAIN_IMAGE" + // ChainATagEnv specifies the tag that Chain A will use. + ChainATagEnv = "CHAIN_A_TAG" + // ChainBTagEnv specifies the tag that Chain B will use. If unspecified + // the value will default to the same value as Chain A. + ChainBTagEnv = "CHAIN_B_TAG" + // GoRelayerTagEnv specifies the go relayer version. Defaults to "main" + GoRelayerTagEnv = "RLY_TAG" + // ChainBinaryEnv binary is the binary that will be used for both chains. + ChainBinaryEnv = "CHAIN_BINARY" + // ChainUpgradeTagEnv specifies the upgrade version tag + ChainUpgradeTagEnv = "CHAIN_UPGRADE_TAG" + // defaultBinary is the default binary that will be used by the chains. + defaultBinary = "simd" + // defaultRlyTag is the tag that will be used if no relayer tag is specified. + // all images are here https://github.com/cosmos/relayer/pkgs/container/relayer/versions + defaultRlyTag = "v2.2.0-rc2" + // defaultChainTag is the tag that will be used for the chains if none is specified. + defaultChainTag = "main" +) + +func getChainImage(binary string) string { + if binary == "" { + binary = defaultBinary + } + return fmt.Sprintf("ghcr.io/cosmos/ibc-go-%s", binary) +} + +// TestConfig holds various fields used in the E2E tests. +type TestConfig struct { + ChainAConfig ChainConfig + ChainBConfig ChainConfig + RlyTag string + UpgradeTag string +} + +type ChainConfig struct { + Image string + Tag string + Binary string +} + +// FromEnv returns a TestConfig constructed from environment variables. +func FromEnv() TestConfig { + chainBinary, ok := os.LookupEnv(ChainBinaryEnv) + if !ok { + chainBinary = defaultBinary + } + + chainATag, ok := os.LookupEnv(ChainATagEnv) + if !ok { + chainATag = defaultChainTag + } + + chainBTag, ok := os.LookupEnv(ChainBTagEnv) + if !ok { + chainBTag = chainATag + } + + rlyTag, ok := os.LookupEnv(GoRelayerTagEnv) + if !ok { + rlyTag = defaultRlyTag + } + + // TODO: remove hard coded value + rlyTag = "andrew-tendermint_v0.37" + + chainAImage := getChainImage(chainBinary) + specifiedChainImage, ok := os.LookupEnv(ChainImageEnv) + if ok { + chainAImage = specifiedChainImage + } + chainBImage := chainAImage + + upgradeTag, ok := os.LookupEnv(ChainUpgradeTagEnv) + if !ok { + upgradeTag = "" + } + + return TestConfig{ + ChainAConfig: ChainConfig{ + Image: chainAImage, + Tag: chainATag, + Binary: chainBinary, + }, + ChainBConfig: ChainConfig{ + Image: chainBImage, + Tag: chainBTag, + Binary: chainBinary, + }, + RlyTag: rlyTag, + UpgradeTag: upgradeTag, + } +} + +func GetChainATag() string { + chainATag, ok := os.LookupEnv(ChainATagEnv) + if !ok { + panic(fmt.Sprintf("no environment variable specified for %s", ChainATagEnv)) + } + return chainATag +} + +func GetChainBTag() string { + chainBTag, ok := os.LookupEnv(ChainBTagEnv) + if !ok { + return GetChainATag() + } + 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. +type ChainOptions struct { + ChainAConfig *ibc.ChainConfig + ChainBConfig *ibc.ChainConfig +} + +// ChainOptionConfiguration enables arbitrary configuration of ChainOptions. +type ChainOptionConfiguration func(options *ChainOptions) + +// DefaultChainOptions returns the default configuration for the chains. +// These options can be configured by passing configuration functions to E2ETestSuite.GetChains. +func DefaultChainOptions() ChainOptions { + tc := FromEnv() + chainACfg := newDefaultSimappConfig(tc.ChainAConfig, "simapp-a", "chain-a", "atoma") + chainBCfg := newDefaultSimappConfig(tc.ChainBConfig, "simapp-b", "chain-b", "atomb") + return ChainOptions{ + ChainAConfig: &chainACfg, + ChainBConfig: &chainBCfg, + } +} + +// newDefaultSimappConfig creates an ibc configuration for simd. +func newDefaultSimappConfig(cc ChainConfig, name, chainID, denom string) ibc.ChainConfig { + return ibc.ChainConfig{ + Type: "cosmos", + Name: name, + ChainID: chainID, + Images: []ibc.DockerImage{ + { + Repository: cc.Image, + Version: cc.Tag, + }, + }, + Bin: cc.Binary, + Bech32Prefix: "cosmos", + CoinType: fmt.Sprint(sdk.GetConfig().GetCoinType()), + Denom: denom, + GasPrices: fmt.Sprintf("0.00%s", denom), + GasAdjustment: 1.3, + TrustingPeriod: "508h", + NoHostMount: false, + ModifyGenesis: defaultModifyGenesis(), + } +} + +// govGenesisFeatureReleases represents the releases the governance module genesis +// was upgraded from v1beta1 to v1. +var govGenesisFeatureReleases = semverutil.FeatureReleases{ + MajorVersion: "v7", +} + +// defaultModifyGenesis will only modify governance params to ensure the voting period and minimum deposit +// are functional for e2e testing purposes. +// Note: this function intentionally does not use the type defined here https://github.com/tendermint/tendermint/blob/v0.37.0-rc2/types/genesis.go#L38-L46 +// and uses a map[string]interface{} instead. +// This approach prevents the field block.TimeIotaMs from being lost which happened when using the GenesisDoc type from tendermint version v0.37.0. +// ibctest performs the following steps when creating the genesis.json file for chains. +// - 1. Let the chain binary create its own genesis file. +// - 2. Apply any provided functions to modify the bytes of the file. +// - 3. Overwrite the file with the new contents. +// This is a problem because when the tendermint types change, marshalling into the type will cause us to lose +// values if the types have changed in between the version of the chain in the test and the version of tendermint +// imported by the e2e tests. +// By using a raw map[string]interface{} we preserve the values unknown to the e2e tests and can still change +// the values we care about. +// TODO: handle these genesis modifications in a way which is type safe and does not require us to rely on +// map[string]interface{} +func defaultModifyGenesis() func(ibc.ChainConfig, []byte) ([]byte, error) { + const appStateKey = "app_state" + return func(chainConfig ibc.ChainConfig, genbz []byte) ([]byte, error) { + genesisDocMap := map[string]interface{}{} + err := json.Unmarshal(genbz, &genesisDocMap) + if err != nil { + return nil, fmt.Errorf("failed to unmarshal genesis bytes into genesis doc: %w", err) + } + + appStateMap, ok := genesisDocMap[appStateKey].(map[string]interface{}) + if !ok { + return nil, fmt.Errorf("failed to extract to app_state") + } + + govModuleBytes, err := json.Marshal(appStateMap[govtypes.ModuleName]) + if err != nil { + return nil, fmt.Errorf("failed to extract gov genesis bytes: %s", err) + } + + govModuleGenesisBytes, err := modifyGovAppState(chainConfig, govModuleBytes) + if err != nil { + return nil, err + } + + govModuleGenesisMap := map[string]interface{}{} + err = json.Unmarshal(govModuleGenesisBytes, &govModuleGenesisMap) + if err != nil { + return nil, fmt.Errorf("failed to unmarshal gov genesis bytes into map: %w", err) + } + + appStateMap[govtypes.ModuleName] = govModuleGenesisMap + genesisDocMap[appStateKey] = appStateMap + + finalGenesisDocBytes, err := json.MarshalIndent(genesisDocMap, "", " ") + if err != nil { + return nil, err + } + + return finalGenesisDocBytes, nil + } +} + +// modifyGovAppState takes the existing gov app state and marshals it to either a govv1 GenesisState +// or a govv1beta1 GenesisState depending on the simapp version. +func modifyGovAppState(chainConfig ibc.ChainConfig, govAppState []byte) ([]byte, error) { + cfg := testutil.MakeTestEncodingConfig() + + cdc := codec.NewProtoCodec(cfg.InterfaceRegistry) + govv1.RegisterInterfaces(cfg.InterfaceRegistry) + govv1beta1.RegisterInterfaces(cfg.InterfaceRegistry) + + shouldUseGovV1 := govGenesisFeatureReleases.IsSupported(chainConfig.Images[0].Version) + + var govGenesisState gogoproto.Message + if shouldUseGovV1 { + govGenesisState = &govv1.GenesisState{} + } else { + govGenesisState = &govv1beta1.GenesisState{} + } + + if err := cdc.UnmarshalJSON(govAppState, govGenesisState); err != nil { + return nil, fmt.Errorf("failed to unmarshal genesis bytes into gov genesis state: %w", err) + } + + switch v := govGenesisState.(type) { + case *govv1.GenesisState: + if v.Params == nil { + v.Params = &govv1.Params{} + } + // set correct minimum deposit using configured denom + v.Params.MinDeposit = sdk.NewCoins(sdk.NewCoin(chainConfig.Denom, govv1beta1.DefaultMinDepositTokens)) + vp := testvalues.VotingPeriod + v.Params.VotingPeriod = &vp + case *govv1beta1.GenesisState: + v.DepositParams.MinDeposit = sdk.NewCoins(sdk.NewCoin(chainConfig.Denom, govv1beta1.DefaultMinDepositTokens)) + v.VotingParams.VotingPeriod = testvalues.VotingPeriod + } + govGenBz, err := cdc.MarshalJSON(govGenesisState) + if err != nil { + return nil, fmt.Errorf("failed to marshal gov genesis state: %w", err) + } + + return govGenBz, nil +} diff --git a/e2e/tests/transfer/authz_test.go b/e2e/tests/transfer/authz_test.go new file mode 100644 index 00000000000..c70dfe0e834 --- /dev/null +++ b/e2e/tests/transfer/authz_test.go @@ -0,0 +1,329 @@ +package transfer + +import ( + "context" + "testing" + + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/cosmos/cosmos-sdk/x/authz" + test "github.com/strangelove-ventures/interchaintest/v7/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/v7/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.FormattedAddress() + + granteeWallet := suite.CreateUserOnChainA(ctx, testvalues.StartingTokenAmount) + granteeAddress := granteeWallet.FormattedAddress() + + receiverWallet := suite.CreateUserOnChainB(ctx, testvalues.StartingTokenAmount) + receiverWalletAddress := receiverWallet.FormattedAddress() + + t.Run("start relayer", func(t *testing.T) { + suite.StartRelayer(relayer) + }) + + // 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}, + }, + }, + } + + 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) + } + + // 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{ + SourcePort: channelA.PortID, + SourceChannel: channelA.ChannelID, + Token: testvalues.DefaultTransferAmount(chainADenom), + Sender: granterAddress, + Receiver: receiverWalletAddress, + 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, receiverWalletAddress, chainBIBCToken.IBCDenom()) + suite.Require().NoError(err) + suite.Require().Equal(testvalues.IBCTransferAmount, actualBalance) + }) + + t.Run("granter grant spend limit reduced", verifyGrantFn(testvalues.StartingTokenAmount-testvalues.IBCTransferAmount)) + + t.Run("re-initialize MsgGrant", createMsgGrantFn) + + t.Run("granter grant was reinitialized", verifyGrantFn(testvalues.StartingTokenAmount)) + + t.Run("revoke access", func(t *testing.T) { + msgRevoke := authz.MsgRevoke{ + Granter: granterAddress, + Grantee: granteeAddress, + MsgTypeUrl: transfertypes.TransferAuthorization{}.MsgTypeURL(), + } + + resp, err := suite.BroadcastMessages(context.TODO(), chainA, granterWallet, &msgRevoke) + suite.AssertValidTxResponse(resp) + suite.Require().NoError(err) + }) + + t.Run("exec unauthorized MsgTransfer", func(t *testing.T) { + transferMsg := transfertypes.MsgTransfer{ + SourcePort: channelA.PortID, + SourceChannel: channelA.ChannelID, + Token: testvalues.DefaultTransferAmount(chainADenom), + Sender: granterAddress, + Receiver: receiverWalletAddress, + 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.Require().NotEqual(0, resp.Code) + suite.Require().Contains(resp.RawLog, authz.ErrNoAuthorizationFound.Error()) + suite.Require().NoError(err) + }) +} + +func (suite *AuthzTransferTestSuite) TestAuthz_InvalidTransferAuthorizations() { + 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.FormattedAddress() + + granteeWallet := suite.CreateUserOnChainA(ctx, testvalues.StartingTokenAmount) + granteeAddress := granteeWallet.FormattedAddress() + + receiverWallet := suite.CreateUserOnChainB(ctx, testvalues.StartingTokenAmount) + receiverWalletAddress := receiverWallet.FormattedAddress() + + t.Run("start relayer", func(t *testing.T) { + suite.StartRelayer(relayer) + }) + + const spendLimit = 1000 + + t.Run("broadcast MsgGrant", func(t *testing.T) { + transferAuth := transfertypes.TransferAuthorization{ + Allocations: []transfertypes.Allocation{ + { + SourcePort: channelA.PortID, + SourceChannel: channelA.ChannelID, + SpendLimit: sdk.NewCoins(sdk.NewCoin(chainADenom, sdk.NewInt(spendLimit))), + AllowList: []string{receiverWalletAddress}, + }, + }, + } + + 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("exceed spend limit", func(t *testing.T) { + const invalidSpendAmount = spendLimit + 1 + + t.Run("broadcast MsgExec for ibc MsgTransfer", func(t *testing.T) { + transferMsg := transfertypes.MsgTransfer{ + SourcePort: channelA.PortID, + SourceChannel: channelA.ChannelID, + Token: sdk.Coin{Denom: chainADenom, Amount: sdk.NewInt(invalidSpendAmount)}, + Sender: granterAddress, + Receiver: receiverWalletAddress, + 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.Require().NotEqual(0, resp.Code) + suite.Require().Contains(resp.RawLog, sdkerrors.ErrInsufficientFunds.Error()) + suite.Require().NoError(err) + }) + + t.Run("verify granter wallet amount", func(t *testing.T) { + actualBalance, err := suite.GetChainANativeBalance(ctx, granterWallet) + suite.Require().NoError(err) + suite.Require().Equal(testvalues.StartingTokenAmount, actualBalance) + }) + + 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, receiverWalletAddress, chainBIBCToken.IBCDenom()) + suite.Require().NoError(err) + suite.Require().Equal(int64(0), actualBalance) + }) + + t.Run("granter grant spend limit unchanged", 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(spendLimit))) + suite.Require().Equal(expectedSpendLimit, transferAuth.Allocations[0].SpendLimit) + }) + }) + + t.Run("send funds to invalid address", func(t *testing.T) { + invalidWallet := suite.CreateUserOnChainB(ctx, testvalues.StartingTokenAmount) + invalidWalletAddress := invalidWallet.FormattedAddress() + + t.Run("broadcast MsgExec for ibc MsgTransfer", func(t *testing.T) { + transferMsg := transfertypes.MsgTransfer{ + SourcePort: channelA.PortID, + SourceChannel: channelA.ChannelID, + Token: sdk.Coin{Denom: chainADenom, Amount: sdk.NewInt(spendLimit)}, + Sender: granterAddress, + Receiver: invalidWalletAddress, + 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.Require().NotEqual(0, resp.Code) + suite.Require().Contains(resp.RawLog, sdkerrors.ErrInvalidAddress.Error()) + suite.Require().NoError(err) + }) + }) +} + +// 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 +} diff --git a/e2e/testsuite/codec.go b/e2e/testsuite/codec.go new file mode 100644 index 00000000000..db0fa340b6c --- /dev/null +++ b/e2e/testsuite/codec.go @@ -0,0 +1,48 @@ +package testsuite + +import ( + "github.com/cosmos/cosmos-sdk/codec" + sdkcodec "github.com/cosmos/cosmos-sdk/crypto/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" + govv1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1" + govv1beta1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1" + grouptypes "github.com/cosmos/cosmos-sdk/x/group" + proposaltypes "github.com/cosmos/cosmos-sdk/x/params/types/proposal" + + icacontrollertypes "github.com/cosmos/ibc-go/v7/modules/apps/27-interchain-accounts/controller/types" + feetypes "github.com/cosmos/ibc-go/v7/modules/apps/29-fee/types" + transfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types" + clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" + simappparams "github.com/cosmos/ibc-go/v7/testing/simapp/params" +) + +func Codec() *codec.ProtoCodec { + cdc, _ := codecAndEncodingConfig() + return cdc +} + +func EncodingConfig() simappparams.EncodingConfig { + _, cfg := codecAndEncodingConfig() + return cfg +} + +func codecAndEncodingConfig() (*codec.ProtoCodec, simappparams.EncodingConfig) { + cfg := simappparams.MakeTestEncodingConfig() + banktypes.RegisterInterfaces(cfg.InterfaceRegistry) + govv1beta1.RegisterInterfaces(cfg.InterfaceRegistry) + govv1.RegisterInterfaces(cfg.InterfaceRegistry) + authtypes.RegisterInterfaces(cfg.InterfaceRegistry) + feetypes.RegisterInterfaces(cfg.InterfaceRegistry) + icacontrollertypes.RegisterInterfaces(cfg.InterfaceRegistry) + sdkcodec.RegisterInterfaces(cfg.InterfaceRegistry) + grouptypes.RegisterInterfaces(cfg.InterfaceRegistry) + proposaltypes.RegisterInterfaces(cfg.InterfaceRegistry) + authz.RegisterInterfaces(cfg.InterfaceRegistry) + transfertypes.RegisterInterfaces(cfg.InterfaceRegistry) + clienttypes.RegisterInterfaces(cfg.InterfaceRegistry) + + cdc := codec.NewProtoCodec(cfg.InterfaceRegistry) + return cdc, cfg +} diff --git a/e2e/testsuite/testsuite.go b/e2e/testsuite/testsuite.go new file mode 100644 index 00000000000..05fb56232ba --- /dev/null +++ b/e2e/testsuite/testsuite.go @@ -0,0 +1,575 @@ +package testsuite + +import ( + "context" + "errors" + "fmt" + "strconv" + "strings" + "time" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/tx" + sdk "github.com/cosmos/cosmos-sdk/types" + signingtypes "github.com/cosmos/cosmos-sdk/types/tx/signing" + authtx "github.com/cosmos/cosmos-sdk/x/auth/tx" + 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" + paramsproposaltypes "github.com/cosmos/cosmos-sdk/x/params/types/proposal" + intertxtypes "github.com/cosmos/interchain-accounts/x/inter-tx/types" + dockerclient "github.com/docker/docker/client" + interchaintest "github.com/strangelove-ventures/interchaintest/v7" + "github.com/strangelove-ventures/interchaintest/v7/chain/cosmos" + "github.com/strangelove-ventures/interchaintest/v7/ibc" + "github.com/strangelove-ventures/interchaintest/v7/testreporter" + test "github.com/strangelove-ventures/interchaintest/v7/testutil" + "github.com/stretchr/testify/suite" + "go.uber.org/zap" + "go.uber.org/zap/zaptest" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" + + "github.com/cosmos/ibc-go/e2e/testconfig" + "github.com/cosmos/ibc-go/e2e/testvalues" + controllertypes "github.com/cosmos/ibc-go/v7/modules/apps/27-interchain-accounts/controller/types" + feetypes "github.com/cosmos/ibc-go/v7/modules/apps/29-fee/types" + transfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types" + clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" + channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" +) + +const ( + // ChainARelayerName is the name given to the relayer wallet on ChainA + ChainARelayerName = "rlyA" + // ChainBRelayerName is the name given to the relayer wallet on ChainB + ChainBRelayerName = "rlyB" + // DefaultGasValue is the default gas value used to configure tx.Factory + DefaultGasValue = 500000 + // emptyLogs is the string value returned from `BroadcastMessages`. There are some situations in which + // the result is empty, when this happens we include the raw logs instead to get as much information + // amount the failure as possible. + emptyLogs = "[]" +) + +// E2ETestSuite has methods and functionality which can be shared among all test suites. +type E2ETestSuite struct { + suite.Suite + + grpcClients map[string]GRPCClients + paths map[string]path + logger *zap.Logger + DockerClient *dockerclient.Client + network string + startRelayerFn func(relayer ibc.Relayer) + + // pathNameIndex is the latest index to be used for generating paths + pathNameIndex uint64 +} + +// GRPCClients holds a reference to any GRPC clients that are needed by the tests. +// These should typically be used for query clients only. If we need to make changes, we should +// use E2ETestSuite.BroadcastMessages to broadcast transactions instead. +type GRPCClients struct { + ClientQueryClient clienttypes.QueryClient + ChannelQueryClient channeltypes.QueryClient + FeeQueryClient feetypes.QueryClient + ICAQueryClient controllertypes.QueryClient + InterTxQueryClient intertxtypes.QueryClient + + // SDK query clients + GovQueryClient govtypesv1beta1.QueryClient + GovQueryClientV1 govtypesv1.QueryClient + 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. +type path struct { + chainA, chainB *cosmos.CosmosChain +} + +// newPath returns a path built from the given chains. +func newPath(chainA, chainB *cosmos.CosmosChain) path { + return path{ + chainA: chainA, + chainB: chainB, + } +} + +// GetRelayerUsers returns two ibc.Wallet instances which can be used for the relayer users +// on the two chains. +func (s *E2ETestSuite) GetRelayerUsers(ctx context.Context, chainOpts ...testconfig.ChainOptionConfiguration) (ibc.Wallet, ibc.Wallet) { + chainA, chainB := s.GetChains(chainOpts...) + chainAAccountBytes, err := chainA.GetAddress(ctx, ChainARelayerName) + s.Require().NoError(err) + + chainBAccountBytes, err := chainB.GetAddress(ctx, ChainBRelayerName) + s.Require().NoError(err) + + chainARelayerUser := cosmos.NewWallet(ChainARelayerName, chainAAccountBytes, "", chainA.Config()) + chainBRelayerUser := cosmos.NewWallet(ChainBRelayerName, chainBAccountBytes, "", chainB.Config()) + + return chainARelayerUser, chainBRelayerUser +} + +// SetupChainsRelayerAndChannel create two chains, a relayer, establishes a connection and creates a channel +// using the given channel options. The relayer returned by this function has not yet started. It should be started +// with E2ETestSuite.StartRelayer if needed. +// This should be called at the start of every test, unless fine grained control is required. +func (s *E2ETestSuite) SetupChainsRelayerAndChannel(ctx context.Context, channelOpts ...func(*ibc.CreateChannelOptions)) (ibc.Relayer, ibc.ChannelOutput) { + chainA, chainB := s.GetChains() + + r := newCosmosRelayer(s.T(), testconfig.FromEnv(), s.logger, s.DockerClient, s.network) + + pathName := s.generatePathName() + + channelOptions := ibc.DefaultChannelOpts() + for _, opt := range channelOpts { + opt(&channelOptions) + } + + ic := interchaintest.NewInterchain(). + AddChain(chainA). + AddChain(chainB). + AddRelayer(r, "r"). + AddLink(interchaintest.InterchainLink{ + Chain1: chainA, + Chain2: chainB, + Relayer: r, + Path: pathName, + CreateChannelOpts: channelOptions, + }) + + eRep := s.GetRelayerExecReporter() + s.Require().NoError(ic.Build(ctx, eRep, interchaintest.InterchainBuildOptions{ + TestName: s.T().Name(), + Client: s.DockerClient, + NetworkID: s.network, + })) + + s.startRelayerFn = func(relayer ibc.Relayer) { + err := relayer.StartRelayer(ctx, eRep, pathName) + s.Require().NoError(err, fmt.Sprintf("failed to start relayer: %s", err)) + s.T().Cleanup(func() { + if !s.T().Failed() { + if err := relayer.StopRelayer(ctx, eRep); err != nil { + s.T().Logf("error stopping relayer: %v", err) + } + } + }) + // wait for relayer to start. + time.Sleep(time.Second * 10) + } + + s.InitGRPCClients(chainA) + s.InitGRPCClients(chainB) + + chainAChannels, err := r.GetChannels(ctx, eRep, chainA.Config().ChainID) + s.Require().NoError(err) + return r, chainAChannels[len(chainAChannels)-1] +} + +// generatePathName generates the path name using the test suites name +func (s *E2ETestSuite) generatePathName() string { + pathName := fmt.Sprintf("%s-path-%d", s.T().Name(), s.pathNameIndex) + s.pathNameIndex++ + return strings.ReplaceAll(pathName, "/", "-") +} + +// generatePath generates the path name using the test suites name +func (s *E2ETestSuite) generatePath(ctx context.Context, relayer ibc.Relayer) string { + chainA, chainB := s.GetChains() + chainAID := chainA.Config().ChainID + chainBID := chainB.Config().ChainID + + pathName := s.generatePathName() + err := relayer.GeneratePath(ctx, s.GetRelayerExecReporter(), chainAID, chainBID, pathName) + s.Require().NoError(err) + + return pathName +} + +// SetupClients creates clients on chainA and chainB using the provided create client options +func (s *E2ETestSuite) SetupClients(ctx context.Context, relayer ibc.Relayer, opts ibc.CreateClientOptions) { + pathName := s.generatePath(ctx, relayer) + err := relayer.CreateClients(ctx, s.GetRelayerExecReporter(), pathName, opts) + s.Require().NoError(err) +} + +// UpdateClients updates clients on chainA and chainB +func (s *E2ETestSuite) UpdateClients(ctx context.Context, relayer ibc.Relayer, pathName string) { + err := relayer.UpdateClients(ctx, s.GetRelayerExecReporter(), pathName) + s.Require().NoError(err) +} + +// GetChains returns two chains that can be used in a test. The pair returned +// is unique to the current test being run. Note: this function does not create containers. +func (s *E2ETestSuite) GetChains(chainOpts ...testconfig.ChainOptionConfiguration) (*cosmos.CosmosChain, *cosmos.CosmosChain) { + if s.paths == nil { + s.paths = map[string]path{} + } + + path, ok := s.paths[s.T().Name()] + if ok { + return path.chainA, path.chainB + } + + chainOptions := testconfig.DefaultChainOptions() + for _, opt := range chainOpts { + opt(&chainOptions) + } + + chainA, chainB := s.createCosmosChains(chainOptions) + path = newPath(chainA, chainB) + s.paths[s.T().Name()] = path + + return path.chainA, path.chainB +} + +// BroadcastMessages broadcasts the provided messages to the given chain and signs them on behalf of the provided user. +// Once the broadcast response is returned, we wait for a few blocks to be created on both chain A and chain B. +func (s *E2ETestSuite) BroadcastMessages(ctx context.Context, chain *cosmos.CosmosChain, user ibc.Wallet, msgs ...sdk.Msg) (sdk.TxResponse, error) { + broadcaster := cosmos.NewBroadcaster(s.T(), chain) + + broadcaster.ConfigureClientContextOptions(func(clientContext client.Context) client.Context { + // use a codec with all the types our tests care about registered. + // BroadcastTx will deserialize the response and will not be able to otherwise. + cdc := Codec() + return clientContext.WithCodec(cdc).WithTxConfig(authtx.NewTxConfig(cdc, []signingtypes.SignMode{signingtypes.SignMode_SIGN_MODE_DIRECT})) + }) + + broadcaster.ConfigureFactoryOptions(func(factory tx.Factory) tx.Factory { + return factory.WithGas(DefaultGasValue) + }) + + resp, err := cosmos.BroadcastTx(ctx, broadcaster, user, msgs...) + if err != nil { + return sdk.TxResponse{}, err + } + + chainA, chainB := s.GetChains() + err = test.WaitForBlocks(ctx, 2, chainA, chainB) + return resp, err +} + +// RegisterCounterPartyPayee broadcasts a MsgRegisterCounterpartyPayee message. +func (s *E2ETestSuite) RegisterCounterPartyPayee(ctx context.Context, chain *cosmos.CosmosChain, + user ibc.Wallet, portID, channelID, relayerAddr, counterpartyPayeeAddr string, +) (sdk.TxResponse, error) { + msg := feetypes.NewMsgRegisterCounterpartyPayee(portID, channelID, relayerAddr, counterpartyPayeeAddr) + return s.BroadcastMessages(ctx, chain, user, msg) +} + +// PayPacketFeeAsync broadcasts a MsgPayPacketFeeAsync message. +func (s *E2ETestSuite) PayPacketFeeAsync( + ctx context.Context, + chain *cosmos.CosmosChain, + user ibc.Wallet, + packetID channeltypes.PacketId, + packetFee feetypes.PacketFee, +) (sdk.TxResponse, error) { + msg := feetypes.NewMsgPayPacketFeeAsync(packetID, packetFee) + return s.BroadcastMessages(ctx, chain, user, msg) +} + +// GetRelayerWallets returns the relayer wallets associated with the chains. +func (s *E2ETestSuite) GetRelayerWallets(relayer ibc.Relayer) (ibc.Wallet, ibc.Wallet, error) { + chainA, chainB := s.GetChains() + chainARelayerWallet, ok := relayer.GetWallet(chainA.Config().ChainID) + if !ok { + return nil, nil, fmt.Errorf("unable to find chain A relayer wallet") + } + + chainBRelayerWallet, ok := relayer.GetWallet(chainB.Config().ChainID) + if !ok { + return nil, nil, fmt.Errorf("unable to find chain B relayer wallet") + } + return chainARelayerWallet, chainBRelayerWallet, nil +} + +// RecoverRelayerWallets adds the corresponding relayer address to the keychain of the chain. +// This is useful if commands executed on the chains expect the relayer information to present in the keychain. +func (s *E2ETestSuite) RecoverRelayerWallets(ctx context.Context, relayer ibc.Relayer) error { + chainARelayerWallet, chainBRelayerWallet, err := s.GetRelayerWallets(relayer) + if err != nil { + return err + } + + chainA, chainB := s.GetChains() + + if err := chainA.RecoverKey(ctx, ChainARelayerName, chainARelayerWallet.Mnemonic()); err != nil { + return fmt.Errorf("could not recover relayer wallet on chain A: %s", err) + } + if err := chainB.RecoverKey(ctx, ChainBRelayerName, chainBRelayerWallet.Mnemonic()); err != nil { + return fmt.Errorf("could not recover relayer wallet on chain B: %s", err) + } + return nil +} + +// Transfer broadcasts a MsgTransfer message. +func (s *E2ETestSuite) Transfer(ctx context.Context, chain *cosmos.CosmosChain, user ibc.Wallet, + portID, channelID string, token sdk.Coin, sender, receiver string, timeoutHeight clienttypes.Height, timeoutTimestamp uint64, memo string, +) (sdk.TxResponse, error) { + msg := transfertypes.NewMsgTransfer(portID, channelID, token, sender, receiver, timeoutHeight, timeoutTimestamp, memo) + return s.BroadcastMessages(ctx, chain, user, msg) +} + +// StartRelayer starts the given relayer. +func (s *E2ETestSuite) StartRelayer(relayer ibc.Relayer) { + if s.startRelayerFn == nil { + panic("cannot start relayer before it is created!") + } + + s.startRelayerFn(relayer) +} + +// StopRelayer stops the given relayer. +func (s *E2ETestSuite) StopRelayer(ctx context.Context, relayer ibc.Relayer) { + err := relayer.StopRelayer(ctx, s.GetRelayerExecReporter()) + s.Require().NoError(err) +} + +// CreateUserOnChainA creates a user with the given amount of funds on chain A. +func (s *E2ETestSuite) CreateUserOnChainA(ctx context.Context, amount int64) ibc.Wallet { + chainA, _ := s.GetChains() + return interchaintest.GetAndFundTestUsers(s.T(), ctx, strings.ReplaceAll(s.T().Name(), " ", "-"), amount, chainA)[0] +} + +// CreateUserOnChainB creates a user with the given amount of funds on chain B. +func (s *E2ETestSuite) CreateUserOnChainB(ctx context.Context, amount int64) ibc.Wallet { + _, chainB := s.GetChains() + return interchaintest.GetAndFundTestUsers(s.T(), ctx, strings.ReplaceAll(s.T().Name(), " ", "-"), amount, chainB)[0] +} + +// GetChainANativeBalance gets the balance of a given user on chain A. +func (s *E2ETestSuite) GetChainANativeBalance(ctx context.Context, user ibc.Wallet) (int64, error) { + chainA, _ := s.GetChains() + return GetNativeChainBalance(ctx, chainA, user) +} + +// GetChainBNativeBalance gets the balance of a given user on chain B. +func (s *E2ETestSuite) GetChainBNativeBalance(ctx context.Context, user ibc.Wallet) (int64, error) { + _, chainB := s.GetChains() + return GetNativeChainBalance(ctx, chainB, user) +} + +// GetChainGRCPClients gets the GRPC clients associated with the given chain. +func (s *E2ETestSuite) GetChainGRCPClients(chain ibc.Chain) GRPCClients { + cs, ok := s.grpcClients[chain.Config().ChainID] + s.Require().True(ok, "chain %s does not have GRPC clients", chain.Config().ChainID) + return cs +} + +// InitGRPCClients establishes GRPC clients with the given chain. +// The created GRPCClients can be retrieved with GetChainGRCPClients. +func (s *E2ETestSuite) InitGRPCClients(chain *cosmos.CosmosChain) { + // Create a connection to the gRPC server. + grpcConn, err := grpc.Dial( + chain.GetHostGRPCAddress(), + grpc.WithTransportCredentials(insecure.NewCredentials()), + ) + s.Require().NoError(err) + s.T().Cleanup(func() { + if err := grpcConn.Close(); err != nil { + s.T().Logf("failed closing GRPC connection to chain %s: %s", chain.Config().ChainID, err) + } + }) + + if s.grpcClients == nil { + s.grpcClients = make(map[string]GRPCClients) + } + + s.grpcClients[chain.Config().ChainID] = GRPCClients{ + ClientQueryClient: clienttypes.NewQueryClient(grpcConn), + ChannelQueryClient: channeltypes.NewQueryClient(grpcConn), + FeeQueryClient: feetypes.NewQueryClient(grpcConn), + ICAQueryClient: controllertypes.NewQueryClient(grpcConn), + InterTxQueryClient: intertxtypes.NewQueryClient(grpcConn), + GovQueryClient: govtypesv1beta1.NewQueryClient(grpcConn), + GovQueryClientV1: govtypesv1.NewQueryClient(grpcConn), + GroupsQueryClient: grouptypes.NewQueryClient(grpcConn), + ParamsQueryClient: paramsproposaltypes.NewQueryClient(grpcConn), + AuthQueryClient: authtypes.NewQueryClient(grpcConn), + AuthZQueryClient: authz.NewQueryClient(grpcConn), + } +} + +// AssertValidTxResponse verifies that an sdk.TxResponse +// has non-empty values. +func (s *E2ETestSuite) AssertValidTxResponse(resp sdk.TxResponse) { + respLogsMsg := resp.Logs.String() + if respLogsMsg == emptyLogs { + respLogsMsg = resp.RawLog + } + s.Require().NotEqual(int64(0), resp.GasUsed, respLogsMsg) + s.Require().NotEqual(int64(0), resp.GasWanted, respLogsMsg) + s.Require().NotEmpty(resp.Events, respLogsMsg) + s.Require().NotEmpty(resp.Data, respLogsMsg) +} + +// AssertPacketRelayed asserts that the packet commitment does not exist on the sending chain. +// The packet commitment will be deleted upon a packet acknowledgement or timeout. +func (s *E2ETestSuite) AssertPacketRelayed(ctx context.Context, chain *cosmos.CosmosChain, portID, channelID string, sequence uint64) { + commitment, _ := s.QueryPacketCommitment(ctx, chain, portID, channelID, sequence) + s.Require().Empty(commitment) +} + +// createCosmosChains creates two separate chains in docker containers. +// test and can be retrieved with GetChains. +func (s *E2ETestSuite) createCosmosChains(chainOptions testconfig.ChainOptions) (*cosmos.CosmosChain, *cosmos.CosmosChain) { + client, network := interchaintest.DockerSetup(s.T()) + + s.logger = zap.NewExample() + s.DockerClient = client + s.network = network + + logger := zaptest.NewLogger(s.T()) + + 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) + return chainA, chainB +} + +// GetRelayerExecReporter returns a testreporter.RelayerExecReporter instances +// using the current test's testing.T. +func (s *E2ETestSuite) GetRelayerExecReporter() *testreporter.RelayerExecReporter { + rep := testreporter.NewNopReporter() + return rep.RelayerExecReporter(s.T()) +} + +// GetTimeoutHeight returns a timeout height of 1000 blocks above the current block height. +// This function should be used when the timeout is never expected to be reached +func (s *E2ETestSuite) GetTimeoutHeight(ctx context.Context, chain *cosmos.CosmosChain) clienttypes.Height { + height, err := chain.Height(ctx) + s.Require().NoError(err) + return clienttypes.NewHeight(clienttypes.ParseChainID(chain.Config().ChainID), uint64(height)+1000) +} + +// GetNativeChainBalance returns the balance of a specific user on a chain using the native denom. +func GetNativeChainBalance(ctx context.Context, chain ibc.Chain, user ibc.Wallet) (int64, error) { + bal, err := chain.GetBalance(ctx, user.FormattedAddress(), chain.Config().Denom) + if err != nil { + return -1, err + } + return bal, nil +} + +// ExecuteGovProposal submits the given governance proposal using the provided user and uses all validators to vote yes on the proposal. +// It ensures the proposal successfully passes. +func (s *E2ETestSuite) ExecuteGovProposal(ctx context.Context, chain *cosmos.CosmosChain, user ibc.Wallet, content govtypesv1beta1.Content) { + sender, err := sdk.AccAddressFromBech32(user.FormattedAddress()) + s.Require().NoError(err) + + msgSubmitProposal, err := govtypesv1beta1.NewMsgSubmitProposal(content, sdk.NewCoins(sdk.NewCoin(chain.Config().Denom, govtypesv1beta1.DefaultMinDepositTokens)), sender) + s.Require().NoError(err) + + txResp, err := s.BroadcastMessages(ctx, chain, user, msgSubmitProposal) + s.Require().NoError(err) + s.AssertValidTxResponse(txResp) + + // TODO: replace with parsed proposal ID from MsgSubmitProposalResponse + // https://github.com/cosmos/ibc-go/issues/2122 + + proposal, err := s.QueryProposal(ctx, chain, 1) + s.Require().NoError(err) + s.Require().Equal(govtypesv1beta1.StatusVotingPeriod, proposal.Status) + + err = chain.VoteOnProposalAllValidators(ctx, "1", cosmos.ProposalVoteYes) + s.Require().NoError(err) + + // ensure voting period has not passed before validators finished voting + proposal, err = s.QueryProposal(ctx, chain, 1) + s.Require().NoError(err) + s.Require().Equal(govtypesv1beta1.StatusVotingPeriod, proposal.Status) + + time.Sleep(testvalues.VotingPeriod) // pass proposal + + proposal, err = s.QueryProposal(ctx, chain, 1) + s.Require().NoError(err) + s.Require().Equal(govtypesv1beta1.StatusPassed, proposal.Status) +} + +// ExecuteGovProposalV1 submits a governance proposal using the provided user and message and uses all validators +// to vote yes on the proposal. It ensures the proposal successfully passes. +func (s *E2ETestSuite) ExecuteGovProposalV1(ctx context.Context, msg sdk.Msg, chain *cosmos.CosmosChain, user ibc.Wallet, proposalID uint64) { + sender, err := sdk.AccAddressFromBech32(user.FormattedAddress()) + s.Require().NoError(err) + + msgs := []sdk.Msg{msg} + msgSubmitProposal, err := govtypesv1.NewMsgSubmitProposal(msgs, sdk.NewCoins(sdk.NewCoin(chain.Config().Denom, govtypesv1.DefaultMinDepositTokens)), sender.String(), "", fmt.Sprintf("e2e gov proposal: %d", proposalID), fmt.Sprintf("executing gov proposal %d", proposalID)) + s.Require().NoError(err) + + resp, err := s.BroadcastMessages(ctx, chain, user, msgSubmitProposal) + s.AssertValidTxResponse(resp) + s.Require().NoError(err) + + s.Require().NoError(chain.VoteOnProposalAllValidators(ctx, strconv.Itoa(int(proposalID)), cosmos.ProposalVoteYes)) + + time.Sleep(testvalues.VotingPeriod) + + proposal, err := s.QueryProposalV1(ctx, chain, proposalID) + s.Require().NoError(err) + s.Require().Equal(govtypesv1.StatusPassed, proposal.Status) +} + +// QueryModuleAccountAddress returns the sdk.AccAddress of a given module name. +func (s *E2ETestSuite) QueryModuleAccountAddress(ctx context.Context, moduleName string, chain *cosmos.CosmosChain) (sdk.AccAddress, error) { + authClient := s.GetChainGRCPClients(chain).AuthQueryClient + + resp, err := authClient.ModuleAccountByName(ctx, &authtypes.QueryModuleAccountByNameRequest{ + Name: moduleName, + }) + if err != nil { + return nil, err + } + + cfg := EncodingConfig() + + var account authtypes.AccountI + if err := cfg.InterfaceRegistry.UnpackAny(resp.Account, &account); err != nil { + return nil, err + } + moduleAccount, ok := account.(authtypes.ModuleAccountI) + if !ok { + return nil, errors.New(fmt.Sprintf("failed to cast account: %T as ModuleAccount", moduleAccount)) + } + + return moduleAccount.GetAddress(), nil +} + +// 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{ + 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)) +} + +// 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 +} diff --git a/e2e/testvalues/values.go b/e2e/testvalues/values.go new file mode 100644 index 00000000000..c4c09e68781 --- /dev/null +++ b/e2e/testvalues/values.go @@ -0,0 +1,45 @@ +package testvalues + +import ( + "fmt" + "time" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/strangelove-ventures/interchaintest/v7/ibc" + + feetypes "github.com/cosmos/ibc-go/v7/modules/apps/29-fee/types" +) + +const ( + StartingTokenAmount int64 = 100_000_000 + IBCTransferAmount int64 = 10_000 + InvalidAddress string = "" + VotingPeriod time.Duration = time.Second * 30 +) + +// ImmediatelyTimeout returns an ibc.IBCTimeout which will cause an IBC transfer to timeout immediately. +func ImmediatelyTimeout() *ibc.IBCTimeout { + return &ibc.IBCTimeout{ + NanoSeconds: 1, + } +} + +func DefaultFee(denom string) feetypes.Fee { + return feetypes.Fee{ + RecvFee: sdk.NewCoins(sdk.NewCoin(denom, sdk.NewInt(50))), + AckFee: sdk.NewCoins(sdk.NewCoin(denom, sdk.NewInt(25))), + TimeoutFee: sdk.NewCoins(sdk.NewCoin(denom, sdk.NewInt(10))), + } +} + +func DefaultTransferAmount(denom string) sdk.Coin { + return sdk.Coin{Denom: denom, Amount: sdk.NewInt(IBCTransferAmount)} +} + +func TendermintClientID(id int) string { + return fmt.Sprintf("07-tendermint-%d", id) +} + +func SolomachineClientID(id int) string { + return fmt.Sprintf("06-solomachine-%d", id) +} diff --git a/go.mod b/go.mod index 90251392e5b..79f7448338a 100644 --- a/go.mod +++ b/go.mod @@ -21,9 +21,16 @@ require ( github.com/stretchr/testify v1.8.1 github.com/tendermint/tendermint v0.34.27 github.com/tendermint/tm-db v0.6.7 +<<<<<<< HEAD google.golang.org/genproto v0.0.0-20221118155620-16455021b5e6 google.golang.org/grpc v1.52.0 google.golang.org/protobuf v1.28.2-0.20220831092852-f930b1dc76e8 +======= + golang.org/x/exp v0.0.0-20221019170559-20944726eadf + google.golang.org/genproto v0.0.0-20221227171554-f9683d7f8bef + google.golang.org/grpc v1.52.3 + google.golang.org/protobuf v1.28.1 +>>>>>>> 6c008ea2 (feat: Added authz support for ics20 (#3079)) gopkg.in/yaml.v2 v2.4.0 ) @@ -141,10 +148,16 @@ require ( github.com/zondax/hid v0.9.1 // indirect github.com/zondax/ledger-go v0.14.1 // indirect go.etcd.io/bbolt v1.3.6 // indirect +<<<<<<< HEAD go.opencensus.io v0.23.0 // indirect golang.org/x/crypto v0.5.0 // indirect golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e // indirect golang.org/x/net v0.7.0 // indirect +======= + go.opencensus.io v0.24.0 // indirect + golang.org/x/crypto v0.4.0 // indirect + golang.org/x/net v0.4.0 // indirect +>>>>>>> 6c008ea2 (feat: Added authz support for ics20 (#3079)) golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783 // indirect golang.org/x/sys v0.5.0 // indirect golang.org/x/term v0.5.0 // indirect diff --git a/modules/apps/transfer/types/ack_test.go b/modules/apps/transfer/types/ack_test.go deleted file mode 100644 index 0b299d434d6..00000000000 --- a/modules/apps/transfer/types/ack_test.go +++ /dev/null @@ -1,29 +0,0 @@ -package types_test - -import ( - "testing" - - "github.com/stretchr/testify/suite" - - ibctesting "github.com/cosmos/ibc-go/v6/testing" -) - -type TypesTestSuite struct { - suite.Suite - - coordinator *ibctesting.Coordinator - - chainA *ibctesting.TestChain - chainB *ibctesting.TestChain -} - -func (suite *TypesTestSuite) SetupTest() { - suite.coordinator = ibctesting.NewCoordinator(suite.T(), 2) - - suite.chainA = suite.coordinator.GetChain(ibctesting.GetChainID(1)) - suite.chainB = suite.coordinator.GetChain(ibctesting.GetChainID(2)) -} - -func TestTypesTestSuite(t *testing.T) { - suite.Run(t, new(TypesTestSuite)) -} diff --git a/modules/apps/transfer/types/authz.pb.go b/modules/apps/transfer/types/authz.pb.go new file mode 100644 index 00000000000..95f24eca332 --- /dev/null +++ b/modules/apps/transfer/types/authz.pb.go @@ -0,0 +1,695 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: ibc/applications/transfer/v1/authz.proto + +package types + +import ( + fmt "fmt" + _ "github.com/cosmos/cosmos-proto" + github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types" + types "github.com/cosmos/cosmos-sdk/types" + _ "github.com/cosmos/gogoproto/gogoproto" + proto "github.com/cosmos/gogoproto/proto" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// Allocation defines the spend limit for a particular port and channel +type Allocation struct { + // the port on which the packet will be sent + SourcePort string `protobuf:"bytes,1,opt,name=source_port,json=sourcePort,proto3" json:"source_port,omitempty" yaml:"source_port"` + // the channel by which the packet will be sent + SourceChannel string `protobuf:"bytes,2,opt,name=source_channel,json=sourceChannel,proto3" json:"source_channel,omitempty" yaml:"source_channel"` + // spend limitation on the channel + SpendLimit github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,3,rep,name=spend_limit,json=spendLimit,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"spend_limit"` + // allow list of receivers, an empty allow list permits any receiver address + AllowList []string `protobuf:"bytes,4,rep,name=allow_list,json=allowList,proto3" json:"allow_list,omitempty"` +} + +func (m *Allocation) Reset() { *m = Allocation{} } +func (m *Allocation) String() string { return proto.CompactTextString(m) } +func (*Allocation) ProtoMessage() {} +func (*Allocation) Descriptor() ([]byte, []int) { + return fileDescriptor_b1a28b55d17325aa, []int{0} +} +func (m *Allocation) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Allocation) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Allocation.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *Allocation) XXX_Merge(src proto.Message) { + xxx_messageInfo_Allocation.Merge(m, src) +} +func (m *Allocation) XXX_Size() int { + return m.Size() +} +func (m *Allocation) XXX_DiscardUnknown() { + xxx_messageInfo_Allocation.DiscardUnknown(m) +} + +var xxx_messageInfo_Allocation proto.InternalMessageInfo + +func (m *Allocation) GetSourcePort() string { + if m != nil { + return m.SourcePort + } + return "" +} + +func (m *Allocation) GetSourceChannel() string { + if m != nil { + return m.SourceChannel + } + return "" +} + +func (m *Allocation) GetSpendLimit() github_com_cosmos_cosmos_sdk_types.Coins { + if m != nil { + return m.SpendLimit + } + return nil +} + +func (m *Allocation) GetAllowList() []string { + if m != nil { + return m.AllowList + } + return nil +} + +// TransferAuthorization allows the grantee to spend up to spend_limit coins from +// the granter's account for ibc transfer on a specific channel +type TransferAuthorization struct { + // port and channel amounts + Allocations []Allocation `protobuf:"bytes,1,rep,name=allocations,proto3" json:"allocations"` +} + +func (m *TransferAuthorization) Reset() { *m = TransferAuthorization{} } +func (m *TransferAuthorization) String() string { return proto.CompactTextString(m) } +func (*TransferAuthorization) ProtoMessage() {} +func (*TransferAuthorization) Descriptor() ([]byte, []int) { + return fileDescriptor_b1a28b55d17325aa, []int{1} +} +func (m *TransferAuthorization) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *TransferAuthorization) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_TransferAuthorization.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *TransferAuthorization) XXX_Merge(src proto.Message) { + xxx_messageInfo_TransferAuthorization.Merge(m, src) +} +func (m *TransferAuthorization) XXX_Size() int { + return m.Size() +} +func (m *TransferAuthorization) XXX_DiscardUnknown() { + xxx_messageInfo_TransferAuthorization.DiscardUnknown(m) +} + +var xxx_messageInfo_TransferAuthorization proto.InternalMessageInfo + +func (m *TransferAuthorization) GetAllocations() []Allocation { + if m != nil { + return m.Allocations + } + return nil +} + +func init() { + proto.RegisterType((*Allocation)(nil), "ibc.applications.transfer.v1.Allocation") + proto.RegisterType((*TransferAuthorization)(nil), "ibc.applications.transfer.v1.TransferAuthorization") +} + +func init() { + proto.RegisterFile("ibc/applications/transfer/v1/authz.proto", fileDescriptor_b1a28b55d17325aa) +} + +var fileDescriptor_b1a28b55d17325aa = []byte{ + // 435 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x52, 0x4d, 0x6e, 0xd3, 0x40, + 0x14, 0x8e, 0x9b, 0x0a, 0x29, 0x13, 0xc1, 0xc2, 0xa2, 0xc8, 0xa9, 0xc0, 0x89, 0xbc, 0x40, 0xde, + 0x64, 0x86, 0xc0, 0x22, 0x52, 0x57, 0x34, 0xdd, 0x76, 0x51, 0x2c, 0x56, 0x6c, 0xa2, 0xf1, 0x64, + 0xb0, 0x47, 0x8c, 0xfd, 0x2c, 0xcf, 0xd8, 0xa8, 0x3d, 0x05, 0x48, 0x9c, 0x82, 0x35, 0x87, 0xa8, + 0x58, 0x75, 0xc9, 0x2a, 0xa0, 0xe4, 0x06, 0x3d, 0x01, 0xf2, 0xcc, 0x14, 0x5c, 0x21, 0xb1, 0xb2, + 0xdf, 0xcf, 0xf7, 0xde, 0xf7, 0xbe, 0xf9, 0x50, 0x2c, 0x52, 0x46, 0x68, 0x55, 0x49, 0xc1, 0xa8, + 0x16, 0x50, 0x2a, 0xa2, 0x6b, 0x5a, 0xaa, 0xf7, 0xbc, 0x26, 0xed, 0x82, 0xd0, 0x46, 0xe7, 0x57, + 0xb8, 0xaa, 0x41, 0x83, 0xff, 0x54, 0xa4, 0x0c, 0xf7, 0x3b, 0xf1, 0x5d, 0x27, 0x6e, 0x17, 0xc7, + 0x13, 0x06, 0xaa, 0x00, 0xb5, 0x36, 0xbd, 0xc4, 0x06, 0x16, 0x78, 0xfc, 0x38, 0x83, 0x0c, 0x6c, + 0xbe, 0xfb, 0x73, 0xd9, 0xd0, 0xf6, 0x90, 0x94, 0x2a, 0x4e, 0xda, 0x45, 0xca, 0x35, 0x5d, 0x10, + 0x06, 0xa2, 0xb4, 0xf5, 0xe8, 0xcb, 0x01, 0x42, 0xa7, 0x52, 0x82, 0x5d, 0xe6, 0x2f, 0xd1, 0x58, + 0x41, 0x53, 0x33, 0xbe, 0xae, 0xa0, 0xd6, 0x81, 0x37, 0xf3, 0xe2, 0xd1, 0xea, 0xc9, 0xed, 0x76, + 0xea, 0x5f, 0xd2, 0x42, 0x9e, 0x44, 0xbd, 0x62, 0x94, 0x20, 0x1b, 0x5d, 0x40, 0xad, 0xfd, 0xd7, + 0xe8, 0x91, 0xab, 0xb1, 0x9c, 0x96, 0x25, 0x97, 0xc1, 0x81, 0xc1, 0x4e, 0x6e, 0xb7, 0xd3, 0xa3, + 0x7b, 0x58, 0x57, 0x8f, 0x92, 0x87, 0x36, 0x71, 0x66, 0x63, 0x5f, 0xa2, 0xb1, 0xaa, 0x78, 0xb9, + 0x59, 0x4b, 0x51, 0x08, 0x1d, 0x0c, 0x67, 0xc3, 0x78, 0xfc, 0x72, 0x82, 0xdd, 0x8d, 0x1d, 0x7f, + 0xec, 0xf8, 0xe3, 0x33, 0x10, 0xe5, 0xea, 0xc5, 0xf5, 0x76, 0x3a, 0xf8, 0xfa, 0x73, 0x1a, 0x67, + 0x42, 0xe7, 0x4d, 0x8a, 0x19, 0x14, 0x4e, 0x10, 0xf7, 0x99, 0xab, 0xcd, 0x07, 0xa2, 0x2f, 0x2b, + 0xae, 0x0c, 0x40, 0x25, 0xc8, 0xcc, 0x3f, 0xef, 0xc6, 0xfb, 0xcf, 0x10, 0xa2, 0x52, 0xc2, 0xc7, + 0xb5, 0x14, 0x4a, 0x07, 0x87, 0xb3, 0x61, 0x3c, 0x4a, 0x46, 0x26, 0x73, 0x2e, 0x94, 0x8e, 0x3e, + 0x7b, 0xe8, 0xe8, 0xad, 0xd3, 0xfd, 0xb4, 0xd1, 0x39, 0xd4, 0xe2, 0xca, 0x2a, 0x74, 0x81, 0xc6, + 0xf4, 0x8f, 0x5e, 0x2a, 0xf0, 0x0c, 0xcd, 0x18, 0xff, 0xef, 0xd5, 0xf0, 0x5f, 0x81, 0x57, 0x87, + 0x1d, 0xeb, 0xa4, 0x3f, 0xe2, 0xe4, 0xf9, 0xf7, 0x6f, 0xf3, 0xc8, 0x9d, 0x69, 0x9d, 0x70, 0x77, + 0xe7, 0xbd, 0xcd, 0xab, 0x37, 0xd7, 0xbb, 0xd0, 0xbb, 0xd9, 0x85, 0xde, 0xaf, 0x5d, 0xe8, 0x7d, + 0xda, 0x87, 0x83, 0x9b, 0x7d, 0x38, 0xf8, 0xb1, 0x0f, 0x07, 0xef, 0x96, 0xff, 0x4a, 0x20, 0x52, + 0x36, 0xcf, 0x80, 0xb4, 0x4b, 0x52, 0xc0, 0xa6, 0x91, 0x5c, 0x75, 0xee, 0xeb, 0xb9, 0xce, 0xe8, + 0x92, 0x3e, 0x30, 0x26, 0x78, 0xf5, 0x3b, 0x00, 0x00, 0xff, 0xff, 0x61, 0xe8, 0x65, 0x9c, 0x9f, + 0x02, 0x00, 0x00, +} + +func (m *Allocation) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *Allocation) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Allocation) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.AllowList) > 0 { + for iNdEx := len(m.AllowList) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.AllowList[iNdEx]) + copy(dAtA[i:], m.AllowList[iNdEx]) + i = encodeVarintAuthz(dAtA, i, uint64(len(m.AllowList[iNdEx]))) + i-- + dAtA[i] = 0x22 + } + } + if len(m.SpendLimit) > 0 { + for iNdEx := len(m.SpendLimit) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.SpendLimit[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintAuthz(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + } + } + if len(m.SourceChannel) > 0 { + i -= len(m.SourceChannel) + copy(dAtA[i:], m.SourceChannel) + i = encodeVarintAuthz(dAtA, i, uint64(len(m.SourceChannel))) + i-- + dAtA[i] = 0x12 + } + if len(m.SourcePort) > 0 { + i -= len(m.SourcePort) + copy(dAtA[i:], m.SourcePort) + i = encodeVarintAuthz(dAtA, i, uint64(len(m.SourcePort))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *TransferAuthorization) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *TransferAuthorization) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *TransferAuthorization) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Allocations) > 0 { + for iNdEx := len(m.Allocations) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Allocations[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintAuthz(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func encodeVarintAuthz(dAtA []byte, offset int, v uint64) int { + offset -= sovAuthz(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *Allocation) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.SourcePort) + if l > 0 { + n += 1 + l + sovAuthz(uint64(l)) + } + l = len(m.SourceChannel) + if l > 0 { + n += 1 + l + sovAuthz(uint64(l)) + } + if len(m.SpendLimit) > 0 { + for _, e := range m.SpendLimit { + l = e.Size() + n += 1 + l + sovAuthz(uint64(l)) + } + } + if len(m.AllowList) > 0 { + for _, s := range m.AllowList { + l = len(s) + n += 1 + l + sovAuthz(uint64(l)) + } + } + return n +} + +func (m *TransferAuthorization) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Allocations) > 0 { + for _, e := range m.Allocations { + l = e.Size() + n += 1 + l + sovAuthz(uint64(l)) + } + } + return n +} + +func sovAuthz(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozAuthz(x uint64) (n int) { + return sovAuthz(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *Allocation) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAuthz + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: Allocation: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Allocation: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field SourcePort", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAuthz + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthAuthz + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthAuthz + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.SourcePort = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field SourceChannel", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAuthz + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthAuthz + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthAuthz + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.SourceChannel = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field SpendLimit", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAuthz + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthAuthz + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthAuthz + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.SpendLimit = append(m.SpendLimit, types.Coin{}) + if err := m.SpendLimit[len(m.SpendLimit)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field AllowList", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAuthz + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthAuthz + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthAuthz + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.AllowList = append(m.AllowList, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipAuthz(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthAuthz + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *TransferAuthorization) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAuthz + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: TransferAuthorization: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: TransferAuthorization: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Allocations", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAuthz + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthAuthz + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthAuthz + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Allocations = append(m.Allocations, Allocation{}) + if err := m.Allocations[len(m.Allocations)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipAuthz(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthAuthz + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipAuthz(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowAuthz + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowAuthz + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowAuthz + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthAuthz + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupAuthz + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthAuthz + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthAuthz = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowAuthz = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupAuthz = fmt.Errorf("proto: unexpected end of group") +) diff --git a/modules/apps/transfer/types/codec.go b/modules/apps/transfer/types/codec.go index 3067cf8dc9d..661a3d8197c 100644 --- a/modules/apps/transfer/types/codec.go +++ b/modules/apps/transfer/types/codec.go @@ -3,6 +3,13 @@ package types import ( "bytes" +<<<<<<< HEAD +======= + "github.com/cosmos/cosmos-sdk/x/authz" + "github.com/cosmos/gogoproto/jsonpb" + "github.com/cosmos/gogoproto/proto" + +>>>>>>> 6c008ea2 (feat: Added authz support for ics20 (#3079)) "github.com/cosmos/cosmos-sdk/codec" codectypes "github.com/cosmos/cosmos-sdk/codec/types" sdk "github.com/cosmos/cosmos-sdk/types" @@ -22,6 +29,11 @@ func RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { func RegisterInterfaces(registry codectypes.InterfaceRegistry) { registry.RegisterImplementations((*sdk.Msg)(nil), &MsgTransfer{}) + registry.RegisterImplementations( + (*authz.Authorization)(nil), + &TransferAuthorization{}, + ) + msgservice.RegisterMsgServiceDesc(registry, &_Msg_serviceDesc) } diff --git a/modules/apps/transfer/types/errors.go b/modules/apps/transfer/types/errors.go index 0f0cb7c42a4..d4f85cf4fa7 100644 --- a/modules/apps/transfer/types/errors.go +++ b/modules/apps/transfer/types/errors.go @@ -14,4 +14,5 @@ var ( ErrSendDisabled = sdkerrors.Register(ModuleName, 7, "fungible token transfers from this chain are disabled") ErrReceiveDisabled = sdkerrors.Register(ModuleName, 8, "fungible token transfers to this chain are disabled") ErrMaxTransferChannels = sdkerrors.Register(ModuleName, 9, "max transfer channels") + ErrInvalidAuthorization = sdkerrors.Register(ModuleName, 10, "invalid transfer authorization") ) diff --git a/modules/apps/transfer/types/transfer_authorization.go b/modules/apps/transfer/types/transfer_authorization.go new file mode 100644 index 00000000000..fed33b0a909 --- /dev/null +++ b/modules/apps/transfer/types/transfer_authorization.go @@ -0,0 +1,127 @@ +package types + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/cosmos/cosmos-sdk/x/authz" + + channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" + host "github.com/cosmos/ibc-go/v7/modules/core/24-host" +) + +const gasCostPerIteration = uint64(10) + +var _ authz.Authorization = &TransferAuthorization{} + +// NewTransferAuthorization creates a new TransferAuthorization object. +func NewTransferAuthorization(allocations ...Allocation) *TransferAuthorization { + return &TransferAuthorization{ + Allocations: allocations, + } +} + +// MsgTypeURL implements Authorization.MsgTypeURL. +func (a TransferAuthorization) MsgTypeURL() string { + return sdk.MsgTypeURL(&MsgTransfer{}) +} + +// Accept implements Authorization.Accept. +func (a TransferAuthorization) Accept(ctx sdk.Context, msg sdk.Msg) (authz.AcceptResponse, error) { + msgTransfer, ok := msg.(*MsgTransfer) + if !ok { + return authz.AcceptResponse{}, sdkerrors.Wrap(sdkerrors.ErrInvalidType, "type mismatch") + } + + for index, allocation := range a.Allocations { + if allocation.SourceChannel == msgTransfer.SourceChannel && allocation.SourcePort == msgTransfer.SourcePort { + limitLeft, isNegative := allocation.SpendLimit.SafeSub(msgTransfer.Token) + if isNegative { + return authz.AcceptResponse{}, sdkerrors.Wrapf(sdkerrors.ErrInsufficientFunds, "requested amount is more than spend limit") + } + + if !isAllowedAddress(ctx, msgTransfer.Receiver, allocation.AllowList) { + return authz.AcceptResponse{}, sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "not allowed address for transfer") + } + + if limitLeft.IsZero() { + a.Allocations = append(a.Allocations[:index], a.Allocations[index+1:]...) + if len(a.Allocations) == 0 { + return authz.AcceptResponse{Accept: true, Delete: true}, nil + } + return authz.AcceptResponse{Accept: true, Delete: false, Updated: &TransferAuthorization{ + Allocations: a.Allocations, + }}, nil + } + a.Allocations[index] = Allocation{ + SourcePort: allocation.SourcePort, + SourceChannel: allocation.SourceChannel, + SpendLimit: limitLeft, + AllowList: allocation.AllowList, + } + + return authz.AcceptResponse{Accept: true, Delete: false, Updated: &TransferAuthorization{ + Allocations: a.Allocations, + }}, nil + } + } + return authz.AcceptResponse{}, sdkerrors.Wrapf(sdkerrors.ErrNotFound, "requested port and channel allocation does not exist") +} + +// ValidateBasic implements Authorization.ValidateBasic. +func (a TransferAuthorization) ValidateBasic() error { + if len(a.Allocations) == 0 { + return sdkerrors.Wrap(ErrInvalidAuthorization, "allocations cannot be empty") + } + + foundChannels := make(map[string]bool, 0) + + for _, allocation := range a.Allocations { + if _, found := foundChannels[allocation.SourceChannel]; found { + return sdkerrors.Wrapf(channeltypes.ErrInvalidChannel, "duplicate source channel ID: %s", allocation.SourceChannel) + } + + foundChannels[allocation.SourceChannel] = true + + if allocation.SpendLimit == nil { + return sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, "spend limit cannot be nil") + } + + if err := allocation.SpendLimit.Validate(); err != nil { + return sdkerrors.Wrapf(sdkerrors.ErrInvalidCoins, err.Error()) + } + + if err := host.PortIdentifierValidator(allocation.SourcePort); err != nil { + return sdkerrors.Wrap(err, "invalid source port ID") + } + + if err := host.ChannelIdentifierValidator(allocation.SourceChannel); err != nil { + return sdkerrors.Wrap(err, "invalid source channel ID") + } + + found := make(map[string]bool, 0) + for i := 0; i < len(allocation.AllowList); i++ { + if found[allocation.AllowList[i]] { + return sdkerrors.Wrapf(ErrInvalidAuthorization, "duplicate entry in allow list %s") + } + found[allocation.AllowList[i]] = true + } + } + + return nil +} + +// isAllowedAddress returns a boolean indicating if the receiver address is valid for transfer. +// gasCostPerIteration gas is consumed for each iteration. +func isAllowedAddress(ctx sdk.Context, receiver string, allowedAddrs []string) bool { + if len(allowedAddrs) == 0 { + return true + } + + for _, addr := range allowedAddrs { + ctx.GasMeter().ConsumeGas(gasCostPerIteration, "transfer authorization") + if addr == receiver { + return true + } + } + return false +} diff --git a/modules/apps/transfer/types/transfer_authorization_test.go b/modules/apps/transfer/types/transfer_authorization_test.go new file mode 100644 index 00000000000..f0f7f3ab0b9 --- /dev/null +++ b/modules/apps/transfer/types/transfer_authorization_test.go @@ -0,0 +1,282 @@ +package types_test + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/authz" + + "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types" + ibctesting "github.com/cosmos/ibc-go/v7/testing" + "github.com/cosmos/ibc-go/v7/testing/mock" +) + +func (suite *TypesTestSuite) TestTransferAuthorizationAccept() { + var ( + msgTransfer types.MsgTransfer + transferAuthz types.TransferAuthorization + ) + + testCases := []struct { + name string + malleate func() + assertResult func(res authz.AcceptResponse, err error) + }{ + { + "success", + func() {}, + func(res authz.AcceptResponse, err error) { + suite.Require().NoError(err) + + suite.Require().True(res.Accept) + suite.Require().True(res.Delete) + suite.Require().Nil(res.Updated) + }, + }, + { + "success: with spend limit updated", + func() { + msgTransfer.Token = sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(50)) + }, + func(res authz.AcceptResponse, err error) { + suite.Require().NoError(err) + + suite.Require().True(res.Accept) + suite.Require().False(res.Delete) + + updatedAuthz, ok := res.Updated.(*types.TransferAuthorization) + suite.Require().True(ok) + + isEqual := updatedAuthz.Allocations[0].SpendLimit.IsEqual(sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(50)))) + suite.Require().True(isEqual) + }, + }, + { + "success: with empty allow list", + func() { + transferAuthz.Allocations[0].AllowList = []string{} + }, + func(res authz.AcceptResponse, err error) { + suite.Require().NoError(err) + + suite.Require().True(res.Accept) + suite.Require().True(res.Delete) + suite.Require().Nil(res.Updated) + }, + }, + { + "success: with multiple allocations", + func() { + alloc := types.Allocation{ + SourcePort: ibctesting.MockPort, + SourceChannel: "channel-9", + SpendLimit: ibctesting.TestCoins, + } + + transferAuthz.Allocations = append(transferAuthz.Allocations, alloc) + }, + func(res authz.AcceptResponse, err error) { + suite.Require().NoError(err) + + suite.Require().True(res.Accept) + suite.Require().False(res.Delete) + + updatedAuthz, ok := res.Updated.(*types.TransferAuthorization) + suite.Require().True(ok) + + // assert spent spendlimit is removed from the list + suite.Require().Len(updatedAuthz.Allocations, 1) + }, + }, + { + "no spend limit set for MsgTransfer port/channel", + func() { + msgTransfer.SourcePort = ibctesting.MockPort + msgTransfer.SourceChannel = "channel-9" + }, + func(res authz.AcceptResponse, err error) { + suite.Require().Error(err) + }, + }, + { + "requested transfer amount is more than the spend limit", + func() { + msgTransfer.Token = sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(1000)) + }, + func(res authz.AcceptResponse, err error) { + suite.Require().Error(err) + }, + }, + { + "receiver address not permitted via allow list", + func() { + msgTransfer.Receiver = suite.chainB.SenderAccount.GetAddress().String() + }, + func(res authz.AcceptResponse, err error) { + suite.Require().Error(err) + }, + }, + } + + for _, tc := range testCases { + suite.Run(tc.name, func() { + suite.SetupTest() + + path := NewTransferPath(suite.chainA, suite.chainB) + suite.coordinator.Setup(path) + + transferAuthz = types.TransferAuthorization{ + Allocations: []types.Allocation{ + { + SourcePort: path.EndpointA.ChannelConfig.PortID, + SourceChannel: path.EndpointA.ChannelID, + SpendLimit: ibctesting.TestCoins, + AllowList: []string{ibctesting.TestAccAddress}, + }, + }, + } + + msgTransfer = types.MsgTransfer{ + SourcePort: path.EndpointA.ChannelConfig.PortID, + SourceChannel: path.EndpointA.ChannelID, + Token: ibctesting.TestCoin, + Sender: suite.chainA.SenderAccount.GetAddress().String(), + Receiver: ibctesting.TestAccAddress, + TimeoutHeight: suite.chainB.GetTimeoutHeight(), + } + + tc.malleate() + + res, err := transferAuthz.Accept(suite.chainA.GetContext(), &msgTransfer) + tc.assertResult(res, err) + }) + } +} + +func (suite *TypesTestSuite) TestTransferAuthorizationMsgTypeURL() { + var transferAuthz types.TransferAuthorization + suite.Require().Equal(sdk.MsgTypeURL(&types.MsgTransfer{}), transferAuthz.MsgTypeURL(), "invalid type url for transfer authorization") +} + +func (suite *TypesTestSuite) TestTransferAuthorizationValidateBasic() { + var transferAuthz types.TransferAuthorization + + testCases := []struct { + name string + malleate func() + expPass bool + }{ + { + "success", + func() {}, + true, + }, + { + "success: empty allow list", + func() { + transferAuthz.Allocations[0].AllowList = []string{} + }, + true, + }, + { + "success: with multiple allocations", + func() { + allocation := types.Allocation{ + SourcePort: types.PortID, + SourceChannel: "channel-1", + SpendLimit: sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100))), + AllowList: []string{}, + } + + transferAuthz.Allocations = append(transferAuthz.Allocations, allocation) + }, + true, + }, + { + "empty allocations", + func() { + transferAuthz = types.TransferAuthorization{Allocations: []types.Allocation{}} + }, + false, + }, + { + "nil allocations", + func() { + transferAuthz = types.TransferAuthorization{} + }, + false, + }, + { + "nil spend limit coins", + func() { + transferAuthz.Allocations[0].SpendLimit = nil + }, + false, + }, + { + "invalid spend limit coins", + func() { + transferAuthz.Allocations[0].SpendLimit = sdk.Coins{sdk.Coin{Denom: ""}} + }, + false, + }, + { + "duplicate entry in allow list", + func() { + transferAuthz.Allocations[0].AllowList = []string{ibctesting.TestAccAddress, ibctesting.TestAccAddress} + }, + false, + }, + { + "invalid port identifier", + func() { + transferAuthz.Allocations[0].SourcePort = "" + }, + false, + }, + { + "invalid channel identifier", + func() { + transferAuthz.Allocations[0].SourceChannel = "" + }, + false, + }, + { + name: "duplicate channel ID", + malleate: func() { + allocation := types.Allocation{ + SourcePort: mock.PortID, + SourceChannel: transferAuthz.Allocations[0].SourceChannel, + SpendLimit: sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100))), + AllowList: []string{ibctesting.TestAccAddress}, + } + + transferAuthz.Allocations = append(transferAuthz.Allocations, allocation) + }, + expPass: false, + }, + } + + for _, tc := range testCases { + suite.Run(tc.name, func() { + transferAuthz = types.TransferAuthorization{ + Allocations: []types.Allocation{ + { + SourcePort: mock.PortID, + SourceChannel: ibctesting.FirstChannelID, + SpendLimit: sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100))), + AllowList: []string{ibctesting.TestAccAddress}, + }, + }, + } + + tc.malleate() + + err := transferAuthz.ValidateBasic() + + if tc.expPass { + suite.Require().NoError(err) + } else { + suite.Require().Error(err) + } + }) + } +} diff --git a/modules/apps/transfer/types/types_test.go b/modules/apps/transfer/types/types_test.go new file mode 100644 index 00000000000..8b6a5fde090 --- /dev/null +++ b/modules/apps/transfer/types/types_test.go @@ -0,0 +1,44 @@ +package types_test + +import ( + "testing" + + "github.com/stretchr/testify/suite" + +<<<<<<< HEAD:modules/apps/transfer/types/ack_test.go + ibctesting "github.com/cosmos/ibc-go/v6/testing" +======= + "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types" + ibctesting "github.com/cosmos/ibc-go/v7/testing" +>>>>>>> 6c008ea2 (feat: Added authz support for ics20 (#3079)):modules/apps/transfer/types/types_test.go +) + +type TypesTestSuite struct { + suite.Suite + + coordinator *ibctesting.Coordinator + + chainA *ibctesting.TestChain + chainB *ibctesting.TestChain +} + +func (suite *TypesTestSuite) SetupTest() { + suite.coordinator = ibctesting.NewCoordinator(suite.T(), 2) + + suite.chainA = suite.coordinator.GetChain(ibctesting.GetChainID(1)) + suite.chainB = suite.coordinator.GetChain(ibctesting.GetChainID(2)) +} + +func NewTransferPath(chainA, chainB *ibctesting.TestChain) *ibctesting.Path { + path := ibctesting.NewPath(chainA, chainB) + path.EndpointA.ChannelConfig.PortID = types.PortID + path.EndpointB.ChannelConfig.PortID = types.PortID + path.EndpointA.ChannelConfig.Version = types.Version + path.EndpointB.ChannelConfig.Version = types.Version + + return path +} + +func TestTypesTestSuite(t *testing.T) { + suite.Run(t, new(TypesTestSuite)) +} diff --git a/proto/ibc/applications/transfer/v1/authz.proto b/proto/ibc/applications/transfer/v1/authz.proto new file mode 100644 index 00000000000..8b27ac9cf7d --- /dev/null +++ b/proto/ibc/applications/transfer/v1/authz.proto @@ -0,0 +1,31 @@ +syntax = "proto3"; + +package ibc.applications.transfer.v1; + +option go_package = "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types"; + +import "cosmos_proto/cosmos.proto"; +import "gogoproto/gogo.proto"; +import "cosmos/base/v1beta1/coin.proto"; + +// Allocation defines the spend limit for a particular port and channel +message Allocation { + // the port on which the packet will be sent + string source_port = 1 [(gogoproto.moretags) = "yaml:\"source_port\""]; + // the channel by which the packet will be sent + string source_channel = 2 [(gogoproto.moretags) = "yaml:\"source_channel\""]; + // spend limitation on the channel + repeated cosmos.base.v1beta1.Coin spend_limit = 3 + [(gogoproto.nullable) = false, (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins"]; + // allow list of receivers, an empty allow list permits any receiver address + repeated string allow_list = 4; +} + +// TransferAuthorization allows the grantee to spend up to spend_limit coins from +// the granter's account for ibc transfer on a specific channel +message TransferAuthorization { + option (cosmos_proto.implements_interface) = "cosmos.authz.v1beta1.Authorization"; + + // port and channel amounts + repeated Allocation allocations = 1 [(gogoproto.nullable) = false]; +} From e3be13a565583c4bd2f108473c81782c7d94bfdf Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Tue, 25 Apr 2023 23:33:19 +0200 Subject: [PATCH 2/5] fix conflicts / fix typo in SDK bump version in changelog --- CHANGELOG.md | 4 +- e2e/testconfig/testconfig.go | 295 --------- e2e/tests/transfer/authz_test.go | 329 ---------- e2e/testsuite/codec.go | 48 -- e2e/testsuite/testsuite.go | 575 ------------------ e2e/testvalues/values.go | 45 -- go.mod | 52 +- go.sum | 76 +-- modules/apps/transfer/types/codec.go | 8 +- .../transfer/types/transfer_authorization.go | 4 +- .../types/transfer_authorization_test.go | 6 +- modules/apps/transfer/types/types_test.go | 6 +- .../ibc/applications/transfer/v1/authz.proto | 2 +- 13 files changed, 71 insertions(+), 1379 deletions(-) delete mode 100644 e2e/testconfig/testconfig.go delete mode 100644 e2e/tests/transfer/authz_test.go delete mode 100644 e2e/testsuite/codec.go delete mode 100644 e2e/testsuite/testsuite.go delete mode 100644 e2e/testvalues/values.go diff --git a/CHANGELOG.md b/CHANGELOG.md index 76bf29d3f88..2bc374457be 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -38,7 +38,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### Dependencies -* [\#3393](https://github.com/cosmos/ibc-go/pull/3393) Bump Cosmos SDK to v0.46.11 and replace Tendermint with CometBFT v0.34.37. +* [\#3393](https://github.com/cosmos/ibc-go/pull/3393) Bump Cosmos SDK to v0.46.12 and replace Tendermint with CometBFT v0.34.37. ### API Breaking @@ -48,6 +48,8 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### Features +* [\#3079](https://github.com/cosmos/ibc-go/pull/3079) Add authz support for ics20. + ### Bug Fixes ## [v6.1.0](https://github.com/cosmos/ibc-go/releases/tag/v6.1.0) - 2022-12-20 diff --git a/e2e/testconfig/testconfig.go b/e2e/testconfig/testconfig.go deleted file mode 100644 index fcd7e262caf..00000000000 --- a/e2e/testconfig/testconfig.go +++ /dev/null @@ -1,295 +0,0 @@ -package testconfig - -import ( - "encoding/json" - "fmt" - "os" - "strings" - - "github.com/cosmos/cosmos-sdk/codec" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/types/module/testutil" - govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" - govv1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1" - govv1beta1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1" - gogoproto "github.com/cosmos/gogoproto/proto" - "github.com/strangelove-ventures/interchaintest/v7/ibc" - - "github.com/cosmos/ibc-go/e2e/semverutil" - "github.com/cosmos/ibc-go/e2e/testvalues" -) - -const ( - // ChainImageEnv specifies the image that the chains will use. If left unspecified, it will - // default to being determined based on the specified binary. E.g. ghcr.io/cosmos/ibc-go-simd - ChainImageEnv = "CHAIN_IMAGE" - // ChainATagEnv specifies the tag that Chain A will use. - ChainATagEnv = "CHAIN_A_TAG" - // ChainBTagEnv specifies the tag that Chain B will use. If unspecified - // the value will default to the same value as Chain A. - ChainBTagEnv = "CHAIN_B_TAG" - // GoRelayerTagEnv specifies the go relayer version. Defaults to "main" - GoRelayerTagEnv = "RLY_TAG" - // ChainBinaryEnv binary is the binary that will be used for both chains. - ChainBinaryEnv = "CHAIN_BINARY" - // ChainUpgradeTagEnv specifies the upgrade version tag - ChainUpgradeTagEnv = "CHAIN_UPGRADE_TAG" - // defaultBinary is the default binary that will be used by the chains. - defaultBinary = "simd" - // defaultRlyTag is the tag that will be used if no relayer tag is specified. - // all images are here https://github.com/cosmos/relayer/pkgs/container/relayer/versions - defaultRlyTag = "v2.2.0-rc2" - // defaultChainTag is the tag that will be used for the chains if none is specified. - defaultChainTag = "main" -) - -func getChainImage(binary string) string { - if binary == "" { - binary = defaultBinary - } - return fmt.Sprintf("ghcr.io/cosmos/ibc-go-%s", binary) -} - -// TestConfig holds various fields used in the E2E tests. -type TestConfig struct { - ChainAConfig ChainConfig - ChainBConfig ChainConfig - RlyTag string - UpgradeTag string -} - -type ChainConfig struct { - Image string - Tag string - Binary string -} - -// FromEnv returns a TestConfig constructed from environment variables. -func FromEnv() TestConfig { - chainBinary, ok := os.LookupEnv(ChainBinaryEnv) - if !ok { - chainBinary = defaultBinary - } - - chainATag, ok := os.LookupEnv(ChainATagEnv) - if !ok { - chainATag = defaultChainTag - } - - chainBTag, ok := os.LookupEnv(ChainBTagEnv) - if !ok { - chainBTag = chainATag - } - - rlyTag, ok := os.LookupEnv(GoRelayerTagEnv) - if !ok { - rlyTag = defaultRlyTag - } - - // TODO: remove hard coded value - rlyTag = "andrew-tendermint_v0.37" - - chainAImage := getChainImage(chainBinary) - specifiedChainImage, ok := os.LookupEnv(ChainImageEnv) - if ok { - chainAImage = specifiedChainImage - } - chainBImage := chainAImage - - upgradeTag, ok := os.LookupEnv(ChainUpgradeTagEnv) - if !ok { - upgradeTag = "" - } - - return TestConfig{ - ChainAConfig: ChainConfig{ - Image: chainAImage, - Tag: chainATag, - Binary: chainBinary, - }, - ChainBConfig: ChainConfig{ - Image: chainBImage, - Tag: chainBTag, - Binary: chainBinary, - }, - RlyTag: rlyTag, - UpgradeTag: upgradeTag, - } -} - -func GetChainATag() string { - chainATag, ok := os.LookupEnv(ChainATagEnv) - if !ok { - panic(fmt.Sprintf("no environment variable specified for %s", ChainATagEnv)) - } - return chainATag -} - -func GetChainBTag() string { - chainBTag, ok := os.LookupEnv(ChainBTagEnv) - if !ok { - return GetChainATag() - } - 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. -type ChainOptions struct { - ChainAConfig *ibc.ChainConfig - ChainBConfig *ibc.ChainConfig -} - -// ChainOptionConfiguration enables arbitrary configuration of ChainOptions. -type ChainOptionConfiguration func(options *ChainOptions) - -// DefaultChainOptions returns the default configuration for the chains. -// These options can be configured by passing configuration functions to E2ETestSuite.GetChains. -func DefaultChainOptions() ChainOptions { - tc := FromEnv() - chainACfg := newDefaultSimappConfig(tc.ChainAConfig, "simapp-a", "chain-a", "atoma") - chainBCfg := newDefaultSimappConfig(tc.ChainBConfig, "simapp-b", "chain-b", "atomb") - return ChainOptions{ - ChainAConfig: &chainACfg, - ChainBConfig: &chainBCfg, - } -} - -// newDefaultSimappConfig creates an ibc configuration for simd. -func newDefaultSimappConfig(cc ChainConfig, name, chainID, denom string) ibc.ChainConfig { - return ibc.ChainConfig{ - Type: "cosmos", - Name: name, - ChainID: chainID, - Images: []ibc.DockerImage{ - { - Repository: cc.Image, - Version: cc.Tag, - }, - }, - Bin: cc.Binary, - Bech32Prefix: "cosmos", - CoinType: fmt.Sprint(sdk.GetConfig().GetCoinType()), - Denom: denom, - GasPrices: fmt.Sprintf("0.00%s", denom), - GasAdjustment: 1.3, - TrustingPeriod: "508h", - NoHostMount: false, - ModifyGenesis: defaultModifyGenesis(), - } -} - -// govGenesisFeatureReleases represents the releases the governance module genesis -// was upgraded from v1beta1 to v1. -var govGenesisFeatureReleases = semverutil.FeatureReleases{ - MajorVersion: "v7", -} - -// defaultModifyGenesis will only modify governance params to ensure the voting period and minimum deposit -// are functional for e2e testing purposes. -// Note: this function intentionally does not use the type defined here https://github.com/tendermint/tendermint/blob/v0.37.0-rc2/types/genesis.go#L38-L46 -// and uses a map[string]interface{} instead. -// This approach prevents the field block.TimeIotaMs from being lost which happened when using the GenesisDoc type from tendermint version v0.37.0. -// ibctest performs the following steps when creating the genesis.json file for chains. -// - 1. Let the chain binary create its own genesis file. -// - 2. Apply any provided functions to modify the bytes of the file. -// - 3. Overwrite the file with the new contents. -// This is a problem because when the tendermint types change, marshalling into the type will cause us to lose -// values if the types have changed in between the version of the chain in the test and the version of tendermint -// imported by the e2e tests. -// By using a raw map[string]interface{} we preserve the values unknown to the e2e tests and can still change -// the values we care about. -// TODO: handle these genesis modifications in a way which is type safe and does not require us to rely on -// map[string]interface{} -func defaultModifyGenesis() func(ibc.ChainConfig, []byte) ([]byte, error) { - const appStateKey = "app_state" - return func(chainConfig ibc.ChainConfig, genbz []byte) ([]byte, error) { - genesisDocMap := map[string]interface{}{} - err := json.Unmarshal(genbz, &genesisDocMap) - if err != nil { - return nil, fmt.Errorf("failed to unmarshal genesis bytes into genesis doc: %w", err) - } - - appStateMap, ok := genesisDocMap[appStateKey].(map[string]interface{}) - if !ok { - return nil, fmt.Errorf("failed to extract to app_state") - } - - govModuleBytes, err := json.Marshal(appStateMap[govtypes.ModuleName]) - if err != nil { - return nil, fmt.Errorf("failed to extract gov genesis bytes: %s", err) - } - - govModuleGenesisBytes, err := modifyGovAppState(chainConfig, govModuleBytes) - if err != nil { - return nil, err - } - - govModuleGenesisMap := map[string]interface{}{} - err = json.Unmarshal(govModuleGenesisBytes, &govModuleGenesisMap) - if err != nil { - return nil, fmt.Errorf("failed to unmarshal gov genesis bytes into map: %w", err) - } - - appStateMap[govtypes.ModuleName] = govModuleGenesisMap - genesisDocMap[appStateKey] = appStateMap - - finalGenesisDocBytes, err := json.MarshalIndent(genesisDocMap, "", " ") - if err != nil { - return nil, err - } - - return finalGenesisDocBytes, nil - } -} - -// modifyGovAppState takes the existing gov app state and marshals it to either a govv1 GenesisState -// or a govv1beta1 GenesisState depending on the simapp version. -func modifyGovAppState(chainConfig ibc.ChainConfig, govAppState []byte) ([]byte, error) { - cfg := testutil.MakeTestEncodingConfig() - - cdc := codec.NewProtoCodec(cfg.InterfaceRegistry) - govv1.RegisterInterfaces(cfg.InterfaceRegistry) - govv1beta1.RegisterInterfaces(cfg.InterfaceRegistry) - - shouldUseGovV1 := govGenesisFeatureReleases.IsSupported(chainConfig.Images[0].Version) - - var govGenesisState gogoproto.Message - if shouldUseGovV1 { - govGenesisState = &govv1.GenesisState{} - } else { - govGenesisState = &govv1beta1.GenesisState{} - } - - if err := cdc.UnmarshalJSON(govAppState, govGenesisState); err != nil { - return nil, fmt.Errorf("failed to unmarshal genesis bytes into gov genesis state: %w", err) - } - - switch v := govGenesisState.(type) { - case *govv1.GenesisState: - if v.Params == nil { - v.Params = &govv1.Params{} - } - // set correct minimum deposit using configured denom - v.Params.MinDeposit = sdk.NewCoins(sdk.NewCoin(chainConfig.Denom, govv1beta1.DefaultMinDepositTokens)) - vp := testvalues.VotingPeriod - v.Params.VotingPeriod = &vp - case *govv1beta1.GenesisState: - v.DepositParams.MinDeposit = sdk.NewCoins(sdk.NewCoin(chainConfig.Denom, govv1beta1.DefaultMinDepositTokens)) - v.VotingParams.VotingPeriod = testvalues.VotingPeriod - } - govGenBz, err := cdc.MarshalJSON(govGenesisState) - if err != nil { - return nil, fmt.Errorf("failed to marshal gov genesis state: %w", err) - } - - return govGenBz, nil -} diff --git a/e2e/tests/transfer/authz_test.go b/e2e/tests/transfer/authz_test.go deleted file mode 100644 index c70dfe0e834..00000000000 --- a/e2e/tests/transfer/authz_test.go +++ /dev/null @@ -1,329 +0,0 @@ -package transfer - -import ( - "context" - "testing" - - codectypes "github.com/cosmos/cosmos-sdk/codec/types" - sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - "github.com/cosmos/cosmos-sdk/x/authz" - test "github.com/strangelove-ventures/interchaintest/v7/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/v7/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.FormattedAddress() - - granteeWallet := suite.CreateUserOnChainA(ctx, testvalues.StartingTokenAmount) - granteeAddress := granteeWallet.FormattedAddress() - - receiverWallet := suite.CreateUserOnChainB(ctx, testvalues.StartingTokenAmount) - receiverWalletAddress := receiverWallet.FormattedAddress() - - t.Run("start relayer", func(t *testing.T) { - suite.StartRelayer(relayer) - }) - - // 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}, - }, - }, - } - - 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) - } - - // 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{ - SourcePort: channelA.PortID, - SourceChannel: channelA.ChannelID, - Token: testvalues.DefaultTransferAmount(chainADenom), - Sender: granterAddress, - Receiver: receiverWalletAddress, - 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, receiverWalletAddress, chainBIBCToken.IBCDenom()) - suite.Require().NoError(err) - suite.Require().Equal(testvalues.IBCTransferAmount, actualBalance) - }) - - t.Run("granter grant spend limit reduced", verifyGrantFn(testvalues.StartingTokenAmount-testvalues.IBCTransferAmount)) - - t.Run("re-initialize MsgGrant", createMsgGrantFn) - - t.Run("granter grant was reinitialized", verifyGrantFn(testvalues.StartingTokenAmount)) - - t.Run("revoke access", func(t *testing.T) { - msgRevoke := authz.MsgRevoke{ - Granter: granterAddress, - Grantee: granteeAddress, - MsgTypeUrl: transfertypes.TransferAuthorization{}.MsgTypeURL(), - } - - resp, err := suite.BroadcastMessages(context.TODO(), chainA, granterWallet, &msgRevoke) - suite.AssertValidTxResponse(resp) - suite.Require().NoError(err) - }) - - t.Run("exec unauthorized MsgTransfer", func(t *testing.T) { - transferMsg := transfertypes.MsgTransfer{ - SourcePort: channelA.PortID, - SourceChannel: channelA.ChannelID, - Token: testvalues.DefaultTransferAmount(chainADenom), - Sender: granterAddress, - Receiver: receiverWalletAddress, - 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.Require().NotEqual(0, resp.Code) - suite.Require().Contains(resp.RawLog, authz.ErrNoAuthorizationFound.Error()) - suite.Require().NoError(err) - }) -} - -func (suite *AuthzTransferTestSuite) TestAuthz_InvalidTransferAuthorizations() { - 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.FormattedAddress() - - granteeWallet := suite.CreateUserOnChainA(ctx, testvalues.StartingTokenAmount) - granteeAddress := granteeWallet.FormattedAddress() - - receiverWallet := suite.CreateUserOnChainB(ctx, testvalues.StartingTokenAmount) - receiverWalletAddress := receiverWallet.FormattedAddress() - - t.Run("start relayer", func(t *testing.T) { - suite.StartRelayer(relayer) - }) - - const spendLimit = 1000 - - t.Run("broadcast MsgGrant", func(t *testing.T) { - transferAuth := transfertypes.TransferAuthorization{ - Allocations: []transfertypes.Allocation{ - { - SourcePort: channelA.PortID, - SourceChannel: channelA.ChannelID, - SpendLimit: sdk.NewCoins(sdk.NewCoin(chainADenom, sdk.NewInt(spendLimit))), - AllowList: []string{receiverWalletAddress}, - }, - }, - } - - 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("exceed spend limit", func(t *testing.T) { - const invalidSpendAmount = spendLimit + 1 - - t.Run("broadcast MsgExec for ibc MsgTransfer", func(t *testing.T) { - transferMsg := transfertypes.MsgTransfer{ - SourcePort: channelA.PortID, - SourceChannel: channelA.ChannelID, - Token: sdk.Coin{Denom: chainADenom, Amount: sdk.NewInt(invalidSpendAmount)}, - Sender: granterAddress, - Receiver: receiverWalletAddress, - 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.Require().NotEqual(0, resp.Code) - suite.Require().Contains(resp.RawLog, sdkerrors.ErrInsufficientFunds.Error()) - suite.Require().NoError(err) - }) - - t.Run("verify granter wallet amount", func(t *testing.T) { - actualBalance, err := suite.GetChainANativeBalance(ctx, granterWallet) - suite.Require().NoError(err) - suite.Require().Equal(testvalues.StartingTokenAmount, actualBalance) - }) - - 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, receiverWalletAddress, chainBIBCToken.IBCDenom()) - suite.Require().NoError(err) - suite.Require().Equal(int64(0), actualBalance) - }) - - t.Run("granter grant spend limit unchanged", 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(spendLimit))) - suite.Require().Equal(expectedSpendLimit, transferAuth.Allocations[0].SpendLimit) - }) - }) - - t.Run("send funds to invalid address", func(t *testing.T) { - invalidWallet := suite.CreateUserOnChainB(ctx, testvalues.StartingTokenAmount) - invalidWalletAddress := invalidWallet.FormattedAddress() - - t.Run("broadcast MsgExec for ibc MsgTransfer", func(t *testing.T) { - transferMsg := transfertypes.MsgTransfer{ - SourcePort: channelA.PortID, - SourceChannel: channelA.ChannelID, - Token: sdk.Coin{Denom: chainADenom, Amount: sdk.NewInt(spendLimit)}, - Sender: granterAddress, - Receiver: invalidWalletAddress, - 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.Require().NotEqual(0, resp.Code) - suite.Require().Contains(resp.RawLog, sdkerrors.ErrInvalidAddress.Error()) - suite.Require().NoError(err) - }) - }) -} - -// 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 -} diff --git a/e2e/testsuite/codec.go b/e2e/testsuite/codec.go deleted file mode 100644 index db0fa340b6c..00000000000 --- a/e2e/testsuite/codec.go +++ /dev/null @@ -1,48 +0,0 @@ -package testsuite - -import ( - "github.com/cosmos/cosmos-sdk/codec" - sdkcodec "github.com/cosmos/cosmos-sdk/crypto/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" - govv1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1" - govv1beta1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1" - grouptypes "github.com/cosmos/cosmos-sdk/x/group" - proposaltypes "github.com/cosmos/cosmos-sdk/x/params/types/proposal" - - icacontrollertypes "github.com/cosmos/ibc-go/v7/modules/apps/27-interchain-accounts/controller/types" - feetypes "github.com/cosmos/ibc-go/v7/modules/apps/29-fee/types" - transfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types" - clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" - simappparams "github.com/cosmos/ibc-go/v7/testing/simapp/params" -) - -func Codec() *codec.ProtoCodec { - cdc, _ := codecAndEncodingConfig() - return cdc -} - -func EncodingConfig() simappparams.EncodingConfig { - _, cfg := codecAndEncodingConfig() - return cfg -} - -func codecAndEncodingConfig() (*codec.ProtoCodec, simappparams.EncodingConfig) { - cfg := simappparams.MakeTestEncodingConfig() - banktypes.RegisterInterfaces(cfg.InterfaceRegistry) - govv1beta1.RegisterInterfaces(cfg.InterfaceRegistry) - govv1.RegisterInterfaces(cfg.InterfaceRegistry) - authtypes.RegisterInterfaces(cfg.InterfaceRegistry) - feetypes.RegisterInterfaces(cfg.InterfaceRegistry) - icacontrollertypes.RegisterInterfaces(cfg.InterfaceRegistry) - sdkcodec.RegisterInterfaces(cfg.InterfaceRegistry) - grouptypes.RegisterInterfaces(cfg.InterfaceRegistry) - proposaltypes.RegisterInterfaces(cfg.InterfaceRegistry) - authz.RegisterInterfaces(cfg.InterfaceRegistry) - transfertypes.RegisterInterfaces(cfg.InterfaceRegistry) - clienttypes.RegisterInterfaces(cfg.InterfaceRegistry) - - cdc := codec.NewProtoCodec(cfg.InterfaceRegistry) - return cdc, cfg -} diff --git a/e2e/testsuite/testsuite.go b/e2e/testsuite/testsuite.go deleted file mode 100644 index 05fb56232ba..00000000000 --- a/e2e/testsuite/testsuite.go +++ /dev/null @@ -1,575 +0,0 @@ -package testsuite - -import ( - "context" - "errors" - "fmt" - "strconv" - "strings" - "time" - - "github.com/cosmos/cosmos-sdk/client" - "github.com/cosmos/cosmos-sdk/client/tx" - sdk "github.com/cosmos/cosmos-sdk/types" - signingtypes "github.com/cosmos/cosmos-sdk/types/tx/signing" - authtx "github.com/cosmos/cosmos-sdk/x/auth/tx" - 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" - paramsproposaltypes "github.com/cosmos/cosmos-sdk/x/params/types/proposal" - intertxtypes "github.com/cosmos/interchain-accounts/x/inter-tx/types" - dockerclient "github.com/docker/docker/client" - interchaintest "github.com/strangelove-ventures/interchaintest/v7" - "github.com/strangelove-ventures/interchaintest/v7/chain/cosmos" - "github.com/strangelove-ventures/interchaintest/v7/ibc" - "github.com/strangelove-ventures/interchaintest/v7/testreporter" - test "github.com/strangelove-ventures/interchaintest/v7/testutil" - "github.com/stretchr/testify/suite" - "go.uber.org/zap" - "go.uber.org/zap/zaptest" - "google.golang.org/grpc" - "google.golang.org/grpc/credentials/insecure" - - "github.com/cosmos/ibc-go/e2e/testconfig" - "github.com/cosmos/ibc-go/e2e/testvalues" - controllertypes "github.com/cosmos/ibc-go/v7/modules/apps/27-interchain-accounts/controller/types" - feetypes "github.com/cosmos/ibc-go/v7/modules/apps/29-fee/types" - transfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types" - clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" - channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" -) - -const ( - // ChainARelayerName is the name given to the relayer wallet on ChainA - ChainARelayerName = "rlyA" - // ChainBRelayerName is the name given to the relayer wallet on ChainB - ChainBRelayerName = "rlyB" - // DefaultGasValue is the default gas value used to configure tx.Factory - DefaultGasValue = 500000 - // emptyLogs is the string value returned from `BroadcastMessages`. There are some situations in which - // the result is empty, when this happens we include the raw logs instead to get as much information - // amount the failure as possible. - emptyLogs = "[]" -) - -// E2ETestSuite has methods and functionality which can be shared among all test suites. -type E2ETestSuite struct { - suite.Suite - - grpcClients map[string]GRPCClients - paths map[string]path - logger *zap.Logger - DockerClient *dockerclient.Client - network string - startRelayerFn func(relayer ibc.Relayer) - - // pathNameIndex is the latest index to be used for generating paths - pathNameIndex uint64 -} - -// GRPCClients holds a reference to any GRPC clients that are needed by the tests. -// These should typically be used for query clients only. If we need to make changes, we should -// use E2ETestSuite.BroadcastMessages to broadcast transactions instead. -type GRPCClients struct { - ClientQueryClient clienttypes.QueryClient - ChannelQueryClient channeltypes.QueryClient - FeeQueryClient feetypes.QueryClient - ICAQueryClient controllertypes.QueryClient - InterTxQueryClient intertxtypes.QueryClient - - // SDK query clients - GovQueryClient govtypesv1beta1.QueryClient - GovQueryClientV1 govtypesv1.QueryClient - 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. -type path struct { - chainA, chainB *cosmos.CosmosChain -} - -// newPath returns a path built from the given chains. -func newPath(chainA, chainB *cosmos.CosmosChain) path { - return path{ - chainA: chainA, - chainB: chainB, - } -} - -// GetRelayerUsers returns two ibc.Wallet instances which can be used for the relayer users -// on the two chains. -func (s *E2ETestSuite) GetRelayerUsers(ctx context.Context, chainOpts ...testconfig.ChainOptionConfiguration) (ibc.Wallet, ibc.Wallet) { - chainA, chainB := s.GetChains(chainOpts...) - chainAAccountBytes, err := chainA.GetAddress(ctx, ChainARelayerName) - s.Require().NoError(err) - - chainBAccountBytes, err := chainB.GetAddress(ctx, ChainBRelayerName) - s.Require().NoError(err) - - chainARelayerUser := cosmos.NewWallet(ChainARelayerName, chainAAccountBytes, "", chainA.Config()) - chainBRelayerUser := cosmos.NewWallet(ChainBRelayerName, chainBAccountBytes, "", chainB.Config()) - - return chainARelayerUser, chainBRelayerUser -} - -// SetupChainsRelayerAndChannel create two chains, a relayer, establishes a connection and creates a channel -// using the given channel options. The relayer returned by this function has not yet started. It should be started -// with E2ETestSuite.StartRelayer if needed. -// This should be called at the start of every test, unless fine grained control is required. -func (s *E2ETestSuite) SetupChainsRelayerAndChannel(ctx context.Context, channelOpts ...func(*ibc.CreateChannelOptions)) (ibc.Relayer, ibc.ChannelOutput) { - chainA, chainB := s.GetChains() - - r := newCosmosRelayer(s.T(), testconfig.FromEnv(), s.logger, s.DockerClient, s.network) - - pathName := s.generatePathName() - - channelOptions := ibc.DefaultChannelOpts() - for _, opt := range channelOpts { - opt(&channelOptions) - } - - ic := interchaintest.NewInterchain(). - AddChain(chainA). - AddChain(chainB). - AddRelayer(r, "r"). - AddLink(interchaintest.InterchainLink{ - Chain1: chainA, - Chain2: chainB, - Relayer: r, - Path: pathName, - CreateChannelOpts: channelOptions, - }) - - eRep := s.GetRelayerExecReporter() - s.Require().NoError(ic.Build(ctx, eRep, interchaintest.InterchainBuildOptions{ - TestName: s.T().Name(), - Client: s.DockerClient, - NetworkID: s.network, - })) - - s.startRelayerFn = func(relayer ibc.Relayer) { - err := relayer.StartRelayer(ctx, eRep, pathName) - s.Require().NoError(err, fmt.Sprintf("failed to start relayer: %s", err)) - s.T().Cleanup(func() { - if !s.T().Failed() { - if err := relayer.StopRelayer(ctx, eRep); err != nil { - s.T().Logf("error stopping relayer: %v", err) - } - } - }) - // wait for relayer to start. - time.Sleep(time.Second * 10) - } - - s.InitGRPCClients(chainA) - s.InitGRPCClients(chainB) - - chainAChannels, err := r.GetChannels(ctx, eRep, chainA.Config().ChainID) - s.Require().NoError(err) - return r, chainAChannels[len(chainAChannels)-1] -} - -// generatePathName generates the path name using the test suites name -func (s *E2ETestSuite) generatePathName() string { - pathName := fmt.Sprintf("%s-path-%d", s.T().Name(), s.pathNameIndex) - s.pathNameIndex++ - return strings.ReplaceAll(pathName, "/", "-") -} - -// generatePath generates the path name using the test suites name -func (s *E2ETestSuite) generatePath(ctx context.Context, relayer ibc.Relayer) string { - chainA, chainB := s.GetChains() - chainAID := chainA.Config().ChainID - chainBID := chainB.Config().ChainID - - pathName := s.generatePathName() - err := relayer.GeneratePath(ctx, s.GetRelayerExecReporter(), chainAID, chainBID, pathName) - s.Require().NoError(err) - - return pathName -} - -// SetupClients creates clients on chainA and chainB using the provided create client options -func (s *E2ETestSuite) SetupClients(ctx context.Context, relayer ibc.Relayer, opts ibc.CreateClientOptions) { - pathName := s.generatePath(ctx, relayer) - err := relayer.CreateClients(ctx, s.GetRelayerExecReporter(), pathName, opts) - s.Require().NoError(err) -} - -// UpdateClients updates clients on chainA and chainB -func (s *E2ETestSuite) UpdateClients(ctx context.Context, relayer ibc.Relayer, pathName string) { - err := relayer.UpdateClients(ctx, s.GetRelayerExecReporter(), pathName) - s.Require().NoError(err) -} - -// GetChains returns two chains that can be used in a test. The pair returned -// is unique to the current test being run. Note: this function does not create containers. -func (s *E2ETestSuite) GetChains(chainOpts ...testconfig.ChainOptionConfiguration) (*cosmos.CosmosChain, *cosmos.CosmosChain) { - if s.paths == nil { - s.paths = map[string]path{} - } - - path, ok := s.paths[s.T().Name()] - if ok { - return path.chainA, path.chainB - } - - chainOptions := testconfig.DefaultChainOptions() - for _, opt := range chainOpts { - opt(&chainOptions) - } - - chainA, chainB := s.createCosmosChains(chainOptions) - path = newPath(chainA, chainB) - s.paths[s.T().Name()] = path - - return path.chainA, path.chainB -} - -// BroadcastMessages broadcasts the provided messages to the given chain and signs them on behalf of the provided user. -// Once the broadcast response is returned, we wait for a few blocks to be created on both chain A and chain B. -func (s *E2ETestSuite) BroadcastMessages(ctx context.Context, chain *cosmos.CosmosChain, user ibc.Wallet, msgs ...sdk.Msg) (sdk.TxResponse, error) { - broadcaster := cosmos.NewBroadcaster(s.T(), chain) - - broadcaster.ConfigureClientContextOptions(func(clientContext client.Context) client.Context { - // use a codec with all the types our tests care about registered. - // BroadcastTx will deserialize the response and will not be able to otherwise. - cdc := Codec() - return clientContext.WithCodec(cdc).WithTxConfig(authtx.NewTxConfig(cdc, []signingtypes.SignMode{signingtypes.SignMode_SIGN_MODE_DIRECT})) - }) - - broadcaster.ConfigureFactoryOptions(func(factory tx.Factory) tx.Factory { - return factory.WithGas(DefaultGasValue) - }) - - resp, err := cosmos.BroadcastTx(ctx, broadcaster, user, msgs...) - if err != nil { - return sdk.TxResponse{}, err - } - - chainA, chainB := s.GetChains() - err = test.WaitForBlocks(ctx, 2, chainA, chainB) - return resp, err -} - -// RegisterCounterPartyPayee broadcasts a MsgRegisterCounterpartyPayee message. -func (s *E2ETestSuite) RegisterCounterPartyPayee(ctx context.Context, chain *cosmos.CosmosChain, - user ibc.Wallet, portID, channelID, relayerAddr, counterpartyPayeeAddr string, -) (sdk.TxResponse, error) { - msg := feetypes.NewMsgRegisterCounterpartyPayee(portID, channelID, relayerAddr, counterpartyPayeeAddr) - return s.BroadcastMessages(ctx, chain, user, msg) -} - -// PayPacketFeeAsync broadcasts a MsgPayPacketFeeAsync message. -func (s *E2ETestSuite) PayPacketFeeAsync( - ctx context.Context, - chain *cosmos.CosmosChain, - user ibc.Wallet, - packetID channeltypes.PacketId, - packetFee feetypes.PacketFee, -) (sdk.TxResponse, error) { - msg := feetypes.NewMsgPayPacketFeeAsync(packetID, packetFee) - return s.BroadcastMessages(ctx, chain, user, msg) -} - -// GetRelayerWallets returns the relayer wallets associated with the chains. -func (s *E2ETestSuite) GetRelayerWallets(relayer ibc.Relayer) (ibc.Wallet, ibc.Wallet, error) { - chainA, chainB := s.GetChains() - chainARelayerWallet, ok := relayer.GetWallet(chainA.Config().ChainID) - if !ok { - return nil, nil, fmt.Errorf("unable to find chain A relayer wallet") - } - - chainBRelayerWallet, ok := relayer.GetWallet(chainB.Config().ChainID) - if !ok { - return nil, nil, fmt.Errorf("unable to find chain B relayer wallet") - } - return chainARelayerWallet, chainBRelayerWallet, nil -} - -// RecoverRelayerWallets adds the corresponding relayer address to the keychain of the chain. -// This is useful if commands executed on the chains expect the relayer information to present in the keychain. -func (s *E2ETestSuite) RecoverRelayerWallets(ctx context.Context, relayer ibc.Relayer) error { - chainARelayerWallet, chainBRelayerWallet, err := s.GetRelayerWallets(relayer) - if err != nil { - return err - } - - chainA, chainB := s.GetChains() - - if err := chainA.RecoverKey(ctx, ChainARelayerName, chainARelayerWallet.Mnemonic()); err != nil { - return fmt.Errorf("could not recover relayer wallet on chain A: %s", err) - } - if err := chainB.RecoverKey(ctx, ChainBRelayerName, chainBRelayerWallet.Mnemonic()); err != nil { - return fmt.Errorf("could not recover relayer wallet on chain B: %s", err) - } - return nil -} - -// Transfer broadcasts a MsgTransfer message. -func (s *E2ETestSuite) Transfer(ctx context.Context, chain *cosmos.CosmosChain, user ibc.Wallet, - portID, channelID string, token sdk.Coin, sender, receiver string, timeoutHeight clienttypes.Height, timeoutTimestamp uint64, memo string, -) (sdk.TxResponse, error) { - msg := transfertypes.NewMsgTransfer(portID, channelID, token, sender, receiver, timeoutHeight, timeoutTimestamp, memo) - return s.BroadcastMessages(ctx, chain, user, msg) -} - -// StartRelayer starts the given relayer. -func (s *E2ETestSuite) StartRelayer(relayer ibc.Relayer) { - if s.startRelayerFn == nil { - panic("cannot start relayer before it is created!") - } - - s.startRelayerFn(relayer) -} - -// StopRelayer stops the given relayer. -func (s *E2ETestSuite) StopRelayer(ctx context.Context, relayer ibc.Relayer) { - err := relayer.StopRelayer(ctx, s.GetRelayerExecReporter()) - s.Require().NoError(err) -} - -// CreateUserOnChainA creates a user with the given amount of funds on chain A. -func (s *E2ETestSuite) CreateUserOnChainA(ctx context.Context, amount int64) ibc.Wallet { - chainA, _ := s.GetChains() - return interchaintest.GetAndFundTestUsers(s.T(), ctx, strings.ReplaceAll(s.T().Name(), " ", "-"), amount, chainA)[0] -} - -// CreateUserOnChainB creates a user with the given amount of funds on chain B. -func (s *E2ETestSuite) CreateUserOnChainB(ctx context.Context, amount int64) ibc.Wallet { - _, chainB := s.GetChains() - return interchaintest.GetAndFundTestUsers(s.T(), ctx, strings.ReplaceAll(s.T().Name(), " ", "-"), amount, chainB)[0] -} - -// GetChainANativeBalance gets the balance of a given user on chain A. -func (s *E2ETestSuite) GetChainANativeBalance(ctx context.Context, user ibc.Wallet) (int64, error) { - chainA, _ := s.GetChains() - return GetNativeChainBalance(ctx, chainA, user) -} - -// GetChainBNativeBalance gets the balance of a given user on chain B. -func (s *E2ETestSuite) GetChainBNativeBalance(ctx context.Context, user ibc.Wallet) (int64, error) { - _, chainB := s.GetChains() - return GetNativeChainBalance(ctx, chainB, user) -} - -// GetChainGRCPClients gets the GRPC clients associated with the given chain. -func (s *E2ETestSuite) GetChainGRCPClients(chain ibc.Chain) GRPCClients { - cs, ok := s.grpcClients[chain.Config().ChainID] - s.Require().True(ok, "chain %s does not have GRPC clients", chain.Config().ChainID) - return cs -} - -// InitGRPCClients establishes GRPC clients with the given chain. -// The created GRPCClients can be retrieved with GetChainGRCPClients. -func (s *E2ETestSuite) InitGRPCClients(chain *cosmos.CosmosChain) { - // Create a connection to the gRPC server. - grpcConn, err := grpc.Dial( - chain.GetHostGRPCAddress(), - grpc.WithTransportCredentials(insecure.NewCredentials()), - ) - s.Require().NoError(err) - s.T().Cleanup(func() { - if err := grpcConn.Close(); err != nil { - s.T().Logf("failed closing GRPC connection to chain %s: %s", chain.Config().ChainID, err) - } - }) - - if s.grpcClients == nil { - s.grpcClients = make(map[string]GRPCClients) - } - - s.grpcClients[chain.Config().ChainID] = GRPCClients{ - ClientQueryClient: clienttypes.NewQueryClient(grpcConn), - ChannelQueryClient: channeltypes.NewQueryClient(grpcConn), - FeeQueryClient: feetypes.NewQueryClient(grpcConn), - ICAQueryClient: controllertypes.NewQueryClient(grpcConn), - InterTxQueryClient: intertxtypes.NewQueryClient(grpcConn), - GovQueryClient: govtypesv1beta1.NewQueryClient(grpcConn), - GovQueryClientV1: govtypesv1.NewQueryClient(grpcConn), - GroupsQueryClient: grouptypes.NewQueryClient(grpcConn), - ParamsQueryClient: paramsproposaltypes.NewQueryClient(grpcConn), - AuthQueryClient: authtypes.NewQueryClient(grpcConn), - AuthZQueryClient: authz.NewQueryClient(grpcConn), - } -} - -// AssertValidTxResponse verifies that an sdk.TxResponse -// has non-empty values. -func (s *E2ETestSuite) AssertValidTxResponse(resp sdk.TxResponse) { - respLogsMsg := resp.Logs.String() - if respLogsMsg == emptyLogs { - respLogsMsg = resp.RawLog - } - s.Require().NotEqual(int64(0), resp.GasUsed, respLogsMsg) - s.Require().NotEqual(int64(0), resp.GasWanted, respLogsMsg) - s.Require().NotEmpty(resp.Events, respLogsMsg) - s.Require().NotEmpty(resp.Data, respLogsMsg) -} - -// AssertPacketRelayed asserts that the packet commitment does not exist on the sending chain. -// The packet commitment will be deleted upon a packet acknowledgement or timeout. -func (s *E2ETestSuite) AssertPacketRelayed(ctx context.Context, chain *cosmos.CosmosChain, portID, channelID string, sequence uint64) { - commitment, _ := s.QueryPacketCommitment(ctx, chain, portID, channelID, sequence) - s.Require().Empty(commitment) -} - -// createCosmosChains creates two separate chains in docker containers. -// test and can be retrieved with GetChains. -func (s *E2ETestSuite) createCosmosChains(chainOptions testconfig.ChainOptions) (*cosmos.CosmosChain, *cosmos.CosmosChain) { - client, network := interchaintest.DockerSetup(s.T()) - - s.logger = zap.NewExample() - s.DockerClient = client - s.network = network - - logger := zaptest.NewLogger(s.T()) - - 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) - return chainA, chainB -} - -// GetRelayerExecReporter returns a testreporter.RelayerExecReporter instances -// using the current test's testing.T. -func (s *E2ETestSuite) GetRelayerExecReporter() *testreporter.RelayerExecReporter { - rep := testreporter.NewNopReporter() - return rep.RelayerExecReporter(s.T()) -} - -// GetTimeoutHeight returns a timeout height of 1000 blocks above the current block height. -// This function should be used when the timeout is never expected to be reached -func (s *E2ETestSuite) GetTimeoutHeight(ctx context.Context, chain *cosmos.CosmosChain) clienttypes.Height { - height, err := chain.Height(ctx) - s.Require().NoError(err) - return clienttypes.NewHeight(clienttypes.ParseChainID(chain.Config().ChainID), uint64(height)+1000) -} - -// GetNativeChainBalance returns the balance of a specific user on a chain using the native denom. -func GetNativeChainBalance(ctx context.Context, chain ibc.Chain, user ibc.Wallet) (int64, error) { - bal, err := chain.GetBalance(ctx, user.FormattedAddress(), chain.Config().Denom) - if err != nil { - return -1, err - } - return bal, nil -} - -// ExecuteGovProposal submits the given governance proposal using the provided user and uses all validators to vote yes on the proposal. -// It ensures the proposal successfully passes. -func (s *E2ETestSuite) ExecuteGovProposal(ctx context.Context, chain *cosmos.CosmosChain, user ibc.Wallet, content govtypesv1beta1.Content) { - sender, err := sdk.AccAddressFromBech32(user.FormattedAddress()) - s.Require().NoError(err) - - msgSubmitProposal, err := govtypesv1beta1.NewMsgSubmitProposal(content, sdk.NewCoins(sdk.NewCoin(chain.Config().Denom, govtypesv1beta1.DefaultMinDepositTokens)), sender) - s.Require().NoError(err) - - txResp, err := s.BroadcastMessages(ctx, chain, user, msgSubmitProposal) - s.Require().NoError(err) - s.AssertValidTxResponse(txResp) - - // TODO: replace with parsed proposal ID from MsgSubmitProposalResponse - // https://github.com/cosmos/ibc-go/issues/2122 - - proposal, err := s.QueryProposal(ctx, chain, 1) - s.Require().NoError(err) - s.Require().Equal(govtypesv1beta1.StatusVotingPeriod, proposal.Status) - - err = chain.VoteOnProposalAllValidators(ctx, "1", cosmos.ProposalVoteYes) - s.Require().NoError(err) - - // ensure voting period has not passed before validators finished voting - proposal, err = s.QueryProposal(ctx, chain, 1) - s.Require().NoError(err) - s.Require().Equal(govtypesv1beta1.StatusVotingPeriod, proposal.Status) - - time.Sleep(testvalues.VotingPeriod) // pass proposal - - proposal, err = s.QueryProposal(ctx, chain, 1) - s.Require().NoError(err) - s.Require().Equal(govtypesv1beta1.StatusPassed, proposal.Status) -} - -// ExecuteGovProposalV1 submits a governance proposal using the provided user and message and uses all validators -// to vote yes on the proposal. It ensures the proposal successfully passes. -func (s *E2ETestSuite) ExecuteGovProposalV1(ctx context.Context, msg sdk.Msg, chain *cosmos.CosmosChain, user ibc.Wallet, proposalID uint64) { - sender, err := sdk.AccAddressFromBech32(user.FormattedAddress()) - s.Require().NoError(err) - - msgs := []sdk.Msg{msg} - msgSubmitProposal, err := govtypesv1.NewMsgSubmitProposal(msgs, sdk.NewCoins(sdk.NewCoin(chain.Config().Denom, govtypesv1.DefaultMinDepositTokens)), sender.String(), "", fmt.Sprintf("e2e gov proposal: %d", proposalID), fmt.Sprintf("executing gov proposal %d", proposalID)) - s.Require().NoError(err) - - resp, err := s.BroadcastMessages(ctx, chain, user, msgSubmitProposal) - s.AssertValidTxResponse(resp) - s.Require().NoError(err) - - s.Require().NoError(chain.VoteOnProposalAllValidators(ctx, strconv.Itoa(int(proposalID)), cosmos.ProposalVoteYes)) - - time.Sleep(testvalues.VotingPeriod) - - proposal, err := s.QueryProposalV1(ctx, chain, proposalID) - s.Require().NoError(err) - s.Require().Equal(govtypesv1.StatusPassed, proposal.Status) -} - -// QueryModuleAccountAddress returns the sdk.AccAddress of a given module name. -func (s *E2ETestSuite) QueryModuleAccountAddress(ctx context.Context, moduleName string, chain *cosmos.CosmosChain) (sdk.AccAddress, error) { - authClient := s.GetChainGRCPClients(chain).AuthQueryClient - - resp, err := authClient.ModuleAccountByName(ctx, &authtypes.QueryModuleAccountByNameRequest{ - Name: moduleName, - }) - if err != nil { - return nil, err - } - - cfg := EncodingConfig() - - var account authtypes.AccountI - if err := cfg.InterfaceRegistry.UnpackAny(resp.Account, &account); err != nil { - return nil, err - } - moduleAccount, ok := account.(authtypes.ModuleAccountI) - if !ok { - return nil, errors.New(fmt.Sprintf("failed to cast account: %T as ModuleAccount", moduleAccount)) - } - - return moduleAccount.GetAddress(), nil -} - -// 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{ - 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)) -} - -// 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 -} diff --git a/e2e/testvalues/values.go b/e2e/testvalues/values.go deleted file mode 100644 index c4c09e68781..00000000000 --- a/e2e/testvalues/values.go +++ /dev/null @@ -1,45 +0,0 @@ -package testvalues - -import ( - "fmt" - "time" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/strangelove-ventures/interchaintest/v7/ibc" - - feetypes "github.com/cosmos/ibc-go/v7/modules/apps/29-fee/types" -) - -const ( - StartingTokenAmount int64 = 100_000_000 - IBCTransferAmount int64 = 10_000 - InvalidAddress string = "" - VotingPeriod time.Duration = time.Second * 30 -) - -// ImmediatelyTimeout returns an ibc.IBCTimeout which will cause an IBC transfer to timeout immediately. -func ImmediatelyTimeout() *ibc.IBCTimeout { - return &ibc.IBCTimeout{ - NanoSeconds: 1, - } -} - -func DefaultFee(denom string) feetypes.Fee { - return feetypes.Fee{ - RecvFee: sdk.NewCoins(sdk.NewCoin(denom, sdk.NewInt(50))), - AckFee: sdk.NewCoins(sdk.NewCoin(denom, sdk.NewInt(25))), - TimeoutFee: sdk.NewCoins(sdk.NewCoin(denom, sdk.NewInt(10))), - } -} - -func DefaultTransferAmount(denom string) sdk.Coin { - return sdk.Coin{Denom: denom, Amount: sdk.NewInt(IBCTransferAmount)} -} - -func TendermintClientID(id int) string { - return fmt.Sprintf("07-tendermint-%d", id) -} - -func SolomachineClientID(id int) string { - return fmt.Sprintf("06-solomachine-%d", id) -} diff --git a/go.mod b/go.mod index 79f7448338a..24081544f05 100644 --- a/go.mod +++ b/go.mod @@ -8,9 +8,11 @@ require ( cosmossdk.io/math v1.0.0-beta.3 github.com/armon/go-metrics v0.4.1 github.com/confio/ics23/go v0.9.0 + github.com/cosmos/cosmos-proto v1.0.0-alpha8 github.com/cosmos/cosmos-sdk v0.46.12 + github.com/cosmos/gogoproto v1.4.8 github.com/gogo/protobuf v1.3.3 - github.com/golang/protobuf v1.5.2 + github.com/golang/protobuf v1.5.3 github.com/gorilla/mux v1.8.0 github.com/grpc-ecosystem/grpc-gateway v1.16.0 github.com/rakyll/statik v0.1.7 @@ -21,24 +23,17 @@ require ( github.com/stretchr/testify v1.8.1 github.com/tendermint/tendermint v0.34.27 github.com/tendermint/tm-db v0.6.7 -<<<<<<< HEAD - google.golang.org/genproto v0.0.0-20221118155620-16455021b5e6 - google.golang.org/grpc v1.52.0 - google.golang.org/protobuf v1.28.2-0.20220831092852-f930b1dc76e8 -======= - golang.org/x/exp v0.0.0-20221019170559-20944726eadf - google.golang.org/genproto v0.0.0-20221227171554-f9683d7f8bef - google.golang.org/grpc v1.52.3 - google.golang.org/protobuf v1.28.1 ->>>>>>> 6c008ea2 (feat: Added authz support for ics20 (#3079)) + google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f + google.golang.org/grpc v1.54.0 + google.golang.org/protobuf v1.30.0 gopkg.in/yaml.v2 v2.4.0 ) require ( - cloud.google.com/go v0.105.0 // indirect - cloud.google.com/go/compute v1.12.1 // indirect - cloud.google.com/go/compute/metadata v0.2.1 // indirect - cloud.google.com/go/iam v0.7.0 // indirect + cloud.google.com/go v0.107.0 // indirect + cloud.google.com/go/compute v1.15.1 // indirect + cloud.google.com/go/compute/metadata v0.2.3 // indirect + cloud.google.com/go/iam v0.8.0 // indirect cloud.google.com/go/storage v1.27.0 // indirect cosmossdk.io/errors v1.0.0-beta.7 // indirect filippo.io/edwards25519 v1.0.0-rc.1 // indirect @@ -53,13 +48,12 @@ require ( github.com/btcsuite/btcd/btcec/v2 v2.3.2 // indirect github.com/cenkalti/backoff/v4 v4.1.3 // indirect github.com/cespare/xxhash v1.1.0 // indirect - github.com/cespare/xxhash/v2 v2.1.2 // indirect + github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e // indirect github.com/cockroachdb/apd/v2 v2.0.2 // indirect github.com/coinbase/rosetta-sdk-go v0.7.9 // indirect github.com/cometbft/cometbft-db v0.7.0 // indirect github.com/cosmos/btcutil v1.0.5 // indirect - github.com/cosmos/cosmos-proto v1.0.0-alpha8 // indirect github.com/cosmos/go-bip39 v1.0.0 // indirect github.com/cosmos/gorocksdb v1.2.0 // indirect github.com/cosmos/iavl v0.19.5 // indirect @@ -90,7 +84,7 @@ require ( github.com/google/orderedcode v0.0.1 // indirect github.com/google/uuid v1.3.0 // indirect github.com/googleapis/enterprise-certificate-proxy v0.2.0 // indirect - github.com/googleapis/gax-go/v2 v2.6.0 // indirect + github.com/googleapis/gax-go/v2 v2.7.0 // indirect github.com/gorilla/handlers v1.5.1 // indirect github.com/gorilla/websocket v1.5.0 // indirect github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 // indirect @@ -148,22 +142,16 @@ require ( github.com/zondax/hid v0.9.1 // indirect github.com/zondax/ledger-go v0.14.1 // indirect go.etcd.io/bbolt v1.3.6 // indirect -<<<<<<< HEAD - go.opencensus.io v0.23.0 // indirect - golang.org/x/crypto v0.5.0 // indirect - golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e // indirect - golang.org/x/net v0.7.0 // indirect -======= go.opencensus.io v0.24.0 // indirect - golang.org/x/crypto v0.4.0 // indirect - golang.org/x/net v0.4.0 // indirect ->>>>>>> 6c008ea2 (feat: Added authz support for ics20 (#3079)) - golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783 // indirect - golang.org/x/sys v0.5.0 // indirect - golang.org/x/term v0.5.0 // indirect - golang.org/x/text v0.7.0 // indirect + golang.org/x/crypto v0.5.0 // indirect + golang.org/x/exp v0.0.0-20230131160201-f062dba9d201 // indirect + golang.org/x/net v0.9.0 // indirect + golang.org/x/oauth2 v0.4.0 // indirect + golang.org/x/sys v0.7.0 // indirect + golang.org/x/term v0.7.0 // indirect + golang.org/x/text v0.9.0 // indirect golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect - google.golang.org/api v0.102.0 // indirect + google.golang.org/api v0.103.0 // indirect google.golang.org/appengine v1.6.7 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/go.sum b/go.sum index 16ddbd6da44..ad8604b3479 100644 --- a/go.sum +++ b/go.sum @@ -19,8 +19,8 @@ cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHOb cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= -cloud.google.com/go v0.105.0 h1:DNtEKRBAAzeS4KyIory52wWHuClNaXJ5x1F7xa4q+5Y= -cloud.google.com/go v0.105.0/go.mod h1:PrLgOJNe5nfE9UMxKxgXj4mD3voiP+YQ6gdt6KMFOKM= +cloud.google.com/go v0.107.0 h1:qkj22L7bgkl6vIeZDlOY2po43Mx/TIa2Wsa7VR+PEww= +cloud.google.com/go v0.107.0/go.mod h1:wpc2eNrD7hXUTy8EKS10jkxpZBjASrORK7goS+3YX2I= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= @@ -28,14 +28,14 @@ cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUM cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= cloud.google.com/go/bigtable v1.2.0/go.mod h1:JcVAOl45lrTmQfLj7T6TxyMzIN/3FGGcFm+2xVAli2o= -cloud.google.com/go/compute v1.12.1 h1:gKVJMEyqV5c/UnpzjjQbo3Rjvvqpr9B1DFSbJC4OXr0= -cloud.google.com/go/compute v1.12.1/go.mod h1:e8yNOBcBONZU1vJKCvCoDw/4JQsA0dpM4x/6PIIOocU= -cloud.google.com/go/compute/metadata v0.2.1 h1:efOwf5ymceDhK6PKMnnrTHP4pppY5L22mle96M1yP48= -cloud.google.com/go/compute/metadata v0.2.1/go.mod h1:jgHgmJd2RKBGzXqF5LR2EZMGxBkeanZ9wwa75XHJgOM= +cloud.google.com/go/compute v1.15.1 h1:7UGq3QknM33pw5xATlpzeoomNxsacIVvTqTTvbfajmE= +cloud.google.com/go/compute v1.15.1/go.mod h1:bjjoF/NtFUrkD/urWfdHaKuOPDR5nWIs63rR+SXhcpA= +cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= +cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= -cloud.google.com/go/iam v0.7.0 h1:k4MuwOsS7zGJJ+QfZ5vBK8SgHBAvYN/23BWsiihJ1vs= -cloud.google.com/go/iam v0.7.0/go.mod h1:H5Br8wRaDGNc8XP3keLc4unfUUZeyH3Sfl9XpQEYOeg= +cloud.google.com/go/iam v0.8.0 h1:E2osAkZzxI/+8pZcxVLcDtAQx/u+hZXVryUaYQ5O0Kk= +cloud.google.com/go/iam v0.8.0/go.mod h1:lga0/y3iH6CX7sYqypWJ33hf7kkfXJag67naqGESjkE= cloud.google.com/go/longrunning v0.3.0 h1:NjljC+FYPV3uh5/OwWT6pVU+doBqMg2x/rZlE+CamDs= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= @@ -172,8 +172,9 @@ github.com/cespare/cp v0.1.0/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cheggaaa/pb v1.0.27/go.mod h1:pQciLPpbU0oxA0h+VJYYLxO+XeDQb5pZijXscXHm81s= github.com/chzyer/logex v1.1.10 h1:Swpa1K6QvQznwJRcfTfQJmTE72DqScAa40E+fbHEXEE= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= @@ -222,6 +223,8 @@ github.com/cosmos/cosmos-sdk v0.46.12/go.mod h1:bG4AkW9bqc8ycrryyKGQEl3YV9BY2wr6 github.com/cosmos/go-bip39 v0.0.0-20180819234021-555e2067c45d/go.mod h1:tSxLoYXyBmiFeKpvmq4dzayMdCjCnu8uqmCysIGBT2Y= github.com/cosmos/go-bip39 v1.0.0 h1:pcomnQdrdH22njcAatO0yWojsUnCO3y2tNoV1cb6hHY= github.com/cosmos/go-bip39 v1.0.0/go.mod h1:RNJv0H/pOIVgxw6KS7QeX2a0Uo0aKUlfhZ4xuwvCdJw= +github.com/cosmos/gogoproto v1.4.8 h1:BrHKc6WFZt8+jRV71vKSQE+JrfF+JAnzrKo2VP7wIZ4= +github.com/cosmos/gogoproto v1.4.8/go.mod h1:hnb0DIEWTv+wdNzNcqus5xCQXq5+CXauq1FJuurRfVY= github.com/cosmos/gorocksdb v1.2.0 h1:d0l3jJG8M4hBouIZq0mDUHZ+zjOx044J3nGRskwTb4Y= github.com/cosmos/gorocksdb v1.2.0/go.mod h1:aaKvKItm514hKfNJpUJXnnOWeBnk2GL4+Qw9NHizILw= github.com/cosmos/iavl v0.19.5 h1:rGA3hOrgNxgRM5wYcSCxgQBap7fW82WZgY78V9po/iY= @@ -401,8 +404,9 @@ github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QD github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= +github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= @@ -458,8 +462,8 @@ github.com/googleapis/enterprise-certificate-proxy v0.2.0 h1:y8Yozv7SZtlU//QXbez github.com/googleapis/enterprise-certificate-proxy v0.2.0/go.mod h1:8C0jb7/mgJe/9KK8Lm7X9ctZC2t60YyIpYEI16jx0Qg= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= -github.com/googleapis/gax-go/v2 v2.6.0 h1:SXk3ABtQYDT/OH8jAyvEOQ58mgawq5C4o/4/89qN2ZU= -github.com/googleapis/gax-go/v2 v2.6.0/go.mod h1:1mjbznJAPHFpesgE5ucqfYEscaz5kMdcIDwU/6+DDoY= +github.com/googleapis/gax-go/v2 v2.7.0 h1:IcsPKeInNvYi7eqSaDjiZqDDKu5rsmunY0Y1YupQSSQ= +github.com/googleapis/gax-go/v2 v2.7.0/go.mod h1:TEop28CZZQ2y+c0VxMUmu1lV+fQx57QpBWsYpwqHJx8= github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= @@ -965,8 +969,8 @@ go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= -go.opencensus.io v0.23.0 h1:gqCw0LfLxScz8irSi8exQc7fyQ0fKQU/qnC/X8+V/1M= -go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= +go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= +go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= @@ -1014,8 +1018,8 @@ golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= golang.org/x/exp v0.0.0-20200331195152-e8c3332aa8e5/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw= -golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e h1:+WEEuIdZHnUeJJmEUjyYC2gfUMj69yZXw17EnHg/otA= -golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e/go.mod h1:Kr81I6Kryrl9sr8s2FK3vxD90NdsKWRuOIl2O4CvYbA= +golang.org/x/exp v0.0.0-20230131160201-f062dba9d201 h1:BEABXpNXLEz0WxtA+6CQIz2xkg80e+1zrhWyMcq8VzE= +golang.org/x/exp v0.0.0-20230131160201-f062dba9d201/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= @@ -1041,7 +1045,7 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.7.0 h1:LapD9S96VoQRhi/GrNTqeBJFrUjs5UHCAtTlgwA5oZA= +golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8= golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1097,8 +1101,8 @@ golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g= -golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.9.0 h1:aWJ/m6xSmxWBx+V0XRHTlrYrPG56jKsLdTFmsSsCzOM= +golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1110,8 +1114,8 @@ golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= -golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783 h1:nt+Q6cXKz4MosCSpnbMtqiQ8Oz0pxTef2B4Vca2lvfk= -golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= +golang.org/x/oauth2 v0.4.0 h1:NF0gk8LVPg1Ml7SSbGyySuoxdsXitj7TvgvuRxIMc/M= +golang.org/x/oauth2 v0.4.0/go.mod h1:RznEsdpjGAINPTOF0UH/t+xJ75L18YO3Ho6Pyn+uRec= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -1205,13 +1209,13 @@ golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220517195934-5e4e11fc645e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= -golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU= +golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.5.0 h1:n2a8QNdAb0sZNpU9R1ALUXBbY+w51fCQDN+7EdxNBsY= -golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.7.0 h1:BEvjmm5fURWqcfbSKTdpkDXYBrUS1c0m8agp14W48vQ= +golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1221,8 +1225,8 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo= -golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -1288,7 +1292,7 @@ golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.4.0 h1:7mTAgkunk3fr4GAloyyCasadO6h9zSsQZbwvcaIciV4= +golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -1321,8 +1325,8 @@ google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz513 google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= -google.golang.org/api v0.102.0 h1:JxJl2qQ85fRMPNvlZY/enexbxpCjLwGhZUtgfGeQ51I= -google.golang.org/api v0.102.0/go.mod h1:3VFl6/fzoA+qNuS1N1/VfXY4LjoXN/wzeIp7TweWwGo= +google.golang.org/api v0.103.0 h1:9yuVqlu2JCvcLg9p8S3fcFLZij8EPSyvODIY1rkMizQ= +google.golang.org/api v0.103.0/go.mod h1:hGtW6nK1AC+d9si/UBhw8Xli+QMOf6xyNAyJw4qU9w0= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -1376,8 +1380,8 @@ google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210126160654-44e461bb6506/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20221118155620-16455021b5e6 h1:a2S6M0+660BgMNl++4JPlcAO/CjkqYItDEZwkoDQK7c= -google.golang.org/genproto v0.0.0-20221118155620-16455021b5e6/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= +google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f h1:BWUVssLB0HVOSY78gIdvk1dTVYtT1y8SBWtPYuTJ/6w= +google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.19.1/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= @@ -1402,8 +1406,8 @@ google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTp google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.52.0 h1:kd48UiU7EHsV4rnLyOJRuP/Il/UHE7gdDAQ+SZI7nZk= -google.golang.org/grpc v1.52.0/go.mod h1:pu6fVzoFb+NBYNAvQL08ic+lvB2IojljRYuun5vorUY= +google.golang.org/grpc v1.54.0 h1:EhTqbhiYeixwWQtAEZAxmV9MGqcjEU2mFx52xCzNyag= +google.golang.org/grpc v1.54.0/go.mod h1:PUSEXI6iWghWaB6lXM4knEgpJNu2qUcKfDtNci3EC2g= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -1416,8 +1420,8 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.28.2-0.20220831092852-f930b1dc76e8 h1:KR8+MyP7/qOlV+8Af01LtjL04bu7on42eVsxT4EyBQk= -google.golang.org/protobuf v1.28.2-0.20220831092852-f930b1dc76e8/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= +google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/modules/apps/transfer/types/codec.go b/modules/apps/transfer/types/codec.go index 661a3d8197c..aef9c1635b9 100644 --- a/modules/apps/transfer/types/codec.go +++ b/modules/apps/transfer/types/codec.go @@ -3,17 +3,11 @@ package types import ( "bytes" -<<<<<<< HEAD -======= - "github.com/cosmos/cosmos-sdk/x/authz" - "github.com/cosmos/gogoproto/jsonpb" - "github.com/cosmos/gogoproto/proto" - ->>>>>>> 6c008ea2 (feat: Added authz support for ics20 (#3079)) "github.com/cosmos/cosmos-sdk/codec" codectypes "github.com/cosmos/cosmos-sdk/codec/types" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/msgservice" + "github.com/cosmos/cosmos-sdk/x/authz" "github.com/gogo/protobuf/jsonpb" "github.com/gogo/protobuf/proto" ) diff --git a/modules/apps/transfer/types/transfer_authorization.go b/modules/apps/transfer/types/transfer_authorization.go index fed33b0a909..b9f550d6f94 100644 --- a/modules/apps/transfer/types/transfer_authorization.go +++ b/modules/apps/transfer/types/transfer_authorization.go @@ -5,8 +5,8 @@ import ( sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/x/authz" - channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" - host "github.com/cosmos/ibc-go/v7/modules/core/24-host" + channeltypes "github.com/cosmos/ibc-go/v6/modules/core/04-channel/types" + host "github.com/cosmos/ibc-go/v6/modules/core/24-host" ) const gasCostPerIteration = uint64(10) diff --git a/modules/apps/transfer/types/transfer_authorization_test.go b/modules/apps/transfer/types/transfer_authorization_test.go index f0f7f3ab0b9..2e2f51bd81a 100644 --- a/modules/apps/transfer/types/transfer_authorization_test.go +++ b/modules/apps/transfer/types/transfer_authorization_test.go @@ -4,9 +4,9 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/authz" - "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types" - ibctesting "github.com/cosmos/ibc-go/v7/testing" - "github.com/cosmos/ibc-go/v7/testing/mock" + "github.com/cosmos/ibc-go/v6/modules/apps/transfer/types" + ibctesting "github.com/cosmos/ibc-go/v6/testing" + "github.com/cosmos/ibc-go/v6/testing/mock" ) func (suite *TypesTestSuite) TestTransferAuthorizationAccept() { diff --git a/modules/apps/transfer/types/types_test.go b/modules/apps/transfer/types/types_test.go index 8b6a5fde090..108304e5927 100644 --- a/modules/apps/transfer/types/types_test.go +++ b/modules/apps/transfer/types/types_test.go @@ -5,12 +5,8 @@ import ( "github.com/stretchr/testify/suite" -<<<<<<< HEAD:modules/apps/transfer/types/ack_test.go + "github.com/cosmos/ibc-go/v6/modules/apps/transfer/types" ibctesting "github.com/cosmos/ibc-go/v6/testing" -======= - "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types" - ibctesting "github.com/cosmos/ibc-go/v7/testing" ->>>>>>> 6c008ea2 (feat: Added authz support for ics20 (#3079)):modules/apps/transfer/types/types_test.go ) type TypesTestSuite struct { diff --git a/proto/ibc/applications/transfer/v1/authz.proto b/proto/ibc/applications/transfer/v1/authz.proto index 8b27ac9cf7d..53113bf5e11 100644 --- a/proto/ibc/applications/transfer/v1/authz.proto +++ b/proto/ibc/applications/transfer/v1/authz.proto @@ -2,7 +2,7 @@ syntax = "proto3"; package ibc.applications.transfer.v1; -option go_package = "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types"; +option go_package = "github.com/cosmos/ibc-go/v6/modules/apps/transfer/types"; import "cosmos_proto/cosmos.proto"; import "gogoproto/gogo.proto"; From a3cde3be05af5781117f19c713096d105ee25852 Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Tue, 25 Apr 2023 23:34:58 +0200 Subject: [PATCH 3/5] gofumpt --- modules/core/04-channel/keeper/keeper_test.go | 1 - 1 file changed, 1 deletion(-) diff --git a/modules/core/04-channel/keeper/keeper_test.go b/modules/core/04-channel/keeper/keeper_test.go index ac97d72e7c3..953f5067844 100644 --- a/modules/core/04-channel/keeper/keeper_test.go +++ b/modules/core/04-channel/keeper/keeper_test.go @@ -85,7 +85,6 @@ func (suite *KeeperTestSuite) TestGetAppVersion() { // TestGetAllChannelsWithPortPrefix verifies ports are filtered correctly using a port prefix. func (suite *KeeperTestSuite) TestGetAllChannelsWithPortPrefix() { - const ( secondChannelID = "channel-1" differentChannelPortID = "different-portid" From 31b4124526e0609b27b06c0456ec7ed0cfd3340e Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Wed, 26 Apr 2023 00:20:06 +0200 Subject: [PATCH 4/5] add authz transfer documentation --- docs/.vuepress/config.js | 5 +++ docs/apps/transfer/authorizations.md | 47 ++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+) create mode 100644 docs/apps/transfer/authorizations.md diff --git a/docs/.vuepress/config.js b/docs/.vuepress/config.js index 411f0c466f9..f98bda280fa 100644 --- a/docs/.vuepress/config.js +++ b/docs/.vuepress/config.js @@ -277,6 +277,11 @@ module.exports = { directory: false, path: "/apps/transfer/params.html", }, + { + title: "Authorizations", + directory: false, + path: "/apps/transfer/authorizations.html", + }, ], }, ], diff --git a/docs/apps/transfer/authorizations.md b/docs/apps/transfer/authorizations.md new file mode 100644 index 00000000000..6dbbafab59b --- /dev/null +++ b/docs/apps/transfer/authorizations.md @@ -0,0 +1,47 @@ +# `TransferAuthorization` + +`TransferAuthorization` implements the `Authorization` interface for `ibc.applications.transfer.v1.MsgTransfer`. It allows a granter to grant a grantee the privilege to submit MsgTransfer on its behalf. Please see the [Cosmos SDK docs](https://docs.cosmos.network/v0.47/modules/authz) for more details on granting privileges via the `x/authz` module. + +More specifically, the granter allows the grantee to transfer funds that belong to the granter over a specified channel. + +For the specified channel, the granter must be able to specify a spend limit of a specific denomination they wish to allow the grantee to be able to transfer. + +The granter may be able to specify the list of addresses that they allow to receive funds. If empty, then all addresses are allowed. + + +It takes: + +- a `SourcePort` and a `SourceChannel` which together comprise the unique transfer channel identifier over which authorized funds can be transferred. + +- a `SpendLimit` that specifies the maximum amount of tokens the grantee can spend. The `SpendLimit` is updated as the tokens are spent. This `SpendLimit` may also be updated to increase or decrease the limit as the granter wishes. + +- an `AllowList` list that specifies the list of addresses that are allowed to receive funds. If this list is empty, then all addresses are allowed to receive funds from the `TransferAuthorization`. + +Setting a `TransferAuthorization` is expected to fail if: +- the spend limit is nil +- the denomination of the spend limit is an invalid coin type +- the source port ID is invalid +- the source channel ID is invalid +- there are duplicate entries in the `AllowList` + +Below is the `TransferAuthorization` message: + +```golang +func NewTransferAuthorization(allocations ...Allocation) *TransferAuthorization { + return &TransferAuthorization{ + Allocations: allocations, + } +} + +type Allocation struct { + // the port on which the packet will be sent + SourcePort string + // the channel by which the packet will be sent + SourceChannel string + // spend limitation on the channel + SpendLimit sdk.Coins + // allow list of receivers, an empty allow list permits any receiver address + AllowList []string +} + +``` \ No newline at end of file From cb2f40bf5516cbcc6ce5fa584d31076125d03f0a Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Thu, 4 May 2023 10:24:41 +0200 Subject: [PATCH 5/5] rm .github/workflows/e2e-manual-simd.yml --- .github/workflows/e2e-manual-simd.yaml | 85 -------------------------- 1 file changed, 85 deletions(-) delete mode 100644 .github/workflows/e2e-manual-simd.yaml diff --git a/.github/workflows/e2e-manual-simd.yaml b/.github/workflows/e2e-manual-simd.yaml deleted file mode 100644 index 611ad78e9c6..00000000000 --- a/.github/workflows/e2e-manual-simd.yaml +++ /dev/null @@ -1,85 +0,0 @@ -name: Manual E2E (Simd) -on: - # when https://github.com/community/community/discussions/11795 is resolved - # we will be able to dynamically build up the list of valid inputs. - # for now this needs to be manual. - workflow_dispatch: - inputs: - test-entry-point: - description: 'Test entry point' - required: true - type: choice - options: - - TestTransferTestSuite - - TestIncentivizedTransferTestSuite - - TestConnectionTestSuite - - TestInterchainAccountsTestSuite - - TestInterchainAccountsGroupsTestSuite - - TestInterchainAccountsGovTestSuite - - TestIncentivizedInterchainAccountsTestSuite - - TestAuthzTransferTestSuite - chain-image: - description: 'The image to use for chain A' - required: true - type: string - default: "ghcr.io/cosmos/ibc-go-simd" - chain-binary: - description: 'Specify the chain binary to be used' - required: true - type: string - default: "simd" - chain-a-tag: - description: 'The tag to use for chain A' - required: true - type: choice - default: main - options: - - main - - v6.1.0 - - v5.2.0 - - v4.2.0 - - v4.1.1 - - v3.4.0 - - v3.3.1 - - v2.5.0 - - v2.4.2 - chain-a-tag-override: - description: 'Specify an arbitrary tag for chain A' - required: false - type: string - chain-b-tag: - default: v6.0.0 - description: 'The tag to use for chain B' - required: true - type: choice - options: - - main - - v6.1.0 - - v5.2.0 - - v4.2.0 - - v4.1.1 - - v3.4.0 - - v3.3.1 - - v2.5.0 - - v2.4.2 - chain-b-tag-override: - description: 'Specify an arbitrary tag for chain B' - required: false - type: string - relayer-tag: - description: 'The tag to use for the relayer' - required: true - default: "v2.1.2" - type: string - - -jobs: - e2e-manual: - uses: ./.github/workflows/e2e-test-workflow-call.yml - with: - chain-image: "${{ github.event.inputs.chain-image }}" - chain-a-tag: "${{ github.event.inputs.chain-a-tag-override || github.event.inputs.chain-a-tag }}" - chain-b-tag: "${{ github.event.inputs.chain-b-tag-override || github.event.inputs.chain-b-tag }}" - relayer-tag: "${{ github.event.inputs.relayer-tag }}" - test-entry-point: "${{ github.event.inputs.test-entry-point }}" - chain-binary: "${{ github.event.inputs.chain-binary }}"