From 31c96a356645946f8bc10a8beaab85d36c6ec18b Mon Sep 17 00:00:00 2001 From: Yurist-85 Date: Fri, 26 Jul 2024 10:29:22 +0800 Subject: [PATCH] feat: add transfer ownership feature to dao module (#329) * feat: add transfer ownership feature to doa module * test: add tests for transfer ownership feature * chore: rename dao module to ucdao * chore: bump version in Makefile * fix: upgrade handler --------- Co-authored-by: Evgeniy Abramov --- Makefile | 2 +- app/app.go | 46 +- app/upgrades/v1.7.6/handler.go | 2 +- app/upgrades/v1.7.6/upgrades.go | 2 +- app/upgrades/v1.7.7/constants.go | 6 + app/upgrades/v1.7.7/upgrades.go | 20 + proto/haqq/dao/module/v1/module.proto | 2 +- proto/haqq/dao/v1/dao.proto | 6 +- proto/haqq/dao/v1/genesis.proto | 2 +- proto/haqq/dao/v1/query.proto | 2 +- proto/haqq/dao/v1/tx.proto | 23 +- x/dao/keeper/integration_test.go | 293 ---------- x/{dao => ucdao}/client/cli/query.go | 6 +- x/{dao => ucdao}/client/cli/tx.go | 48 +- x/{dao => ucdao}/exported/exported.go | 0 x/{dao => ucdao}/keeper/account_balances.go | 13 +- x/{dao => ucdao}/keeper/genesis.go | 2 +- x/{dao => ucdao}/keeper/grpc_query.go | 2 +- x/ucdao/keeper/integration_test.go | 617 ++++++++++++++++++++ x/{dao => ucdao}/keeper/keeper.go | 30 +- x/{dao => ucdao}/keeper/msg_server.go | 22 +- x/{dao => ucdao}/keeper/params.go | 2 +- x/{dao => ucdao}/keeper/setup_test.go | 2 +- x/{dao => ucdao}/keeper/store.go | 2 +- x/{dao => ucdao}/keeper/total_balance.go | 2 +- x/{dao => ucdao}/keeper/utils.go | 0 x/{dao => ucdao}/module.go | 10 +- x/{dao => ucdao}/spec/README.md | 0 x/{dao => ucdao}/types/balance.go | 2 +- x/{dao => ucdao}/types/codec.go | 4 +- x/{dao => ucdao}/types/dao.pb.go | 0 x/{dao => ucdao}/types/errors.go | 1 + x/{dao => ucdao}/types/expected_keepers.go | 0 x/{dao => ucdao}/types/genesis.go | 0 x/{dao => ucdao}/types/genesis.pb.go | 0 x/{dao => ucdao}/types/keys.go | 5 +- x/{dao => ucdao}/types/msg.go | 43 +- x/{dao => ucdao}/types/params.go | 0 x/{dao => ucdao}/types/querier.go | 0 x/{dao => ucdao}/types/query.pb.go | 0 x/{dao => ucdao}/types/query.pb.gw.go | 0 x/{dao => ucdao}/types/tx.pb.go | 426 +++++++++++++- 42 files changed, 1276 insertions(+), 369 deletions(-) create mode 100644 app/upgrades/v1.7.7/constants.go create mode 100644 app/upgrades/v1.7.7/upgrades.go delete mode 100644 x/dao/keeper/integration_test.go rename x/{dao => ucdao}/client/cli/query.go (94%) rename x/{dao => ucdao}/client/cli/tx.go (55%) rename x/{dao => ucdao}/exported/exported.go (100%) rename x/{dao => ucdao}/keeper/account_balances.go (94%) rename x/{dao => ucdao}/keeper/genesis.go (98%) rename x/{dao => ucdao}/keeper/grpc_query.go (98%) create mode 100644 x/ucdao/keeper/integration_test.go rename x/{dao => ucdao}/keeper/keeper.go (82%) rename x/{dao => ucdao}/keeper/msg_server.go (56%) rename x/{dao => ucdao}/keeper/params.go (94%) rename x/{dao => ucdao}/keeper/setup_test.go (98%) rename x/{dao => ucdao}/keeper/store.go (93%) rename x/{dao => ucdao}/keeper/total_balance.go (98%) rename x/{dao => ucdao}/keeper/utils.go (100%) rename x/{dao => ucdao}/module.go (96%) rename x/{dao => ucdao}/spec/README.md (100%) rename x/{dao => ucdao}/types/balance.go (98%) rename x/{dao => ucdao}/types/codec.go (91%) rename x/{dao => ucdao}/types/dao.pb.go (100%) rename x/{dao => ucdao}/types/errors.go (81%) rename x/{dao => ucdao}/types/expected_keepers.go (100%) rename x/{dao => ucdao}/types/genesis.go (100%) rename x/{dao => ucdao}/types/genesis.pb.go (100%) rename x/{dao => ucdao}/types/keys.go (94%) rename x/{dao => ucdao}/types/msg.go (50%) rename x/{dao => ucdao}/types/params.go (100%) rename x/{dao => ucdao}/types/querier.go (100%) rename x/{dao => ucdao}/types/query.pb.go (100%) rename x/{dao => ucdao}/types/query.pb.gw.go (100%) rename x/{dao => ucdao}/types/tx.pb.go (51%) diff --git a/Makefile b/Makefile index da6c70ca..ae65a1e7 100644 --- a/Makefile +++ b/Makefile @@ -6,7 +6,7 @@ DIFF_TAG=$(shell git rev-list --tags="v*" --max-count=1 --not $(shell git rev-li DEFAULT_TAG=$(shell git rev-list --tags="v*" --max-count=1) # VERSION ?= $(shell echo $(shell git describe --tags $(or $(DIFF_TAG), $(DEFAULT_TAG))) | sed 's/^v//') -VERSION := "1.7.6" +VERSION := "1.7.7" CBFTVERSION := $(shell go list -m github.com/cometbft/cometbft | sed 's:.* ::') COMMIT := $(shell git log -1 --format='%H') LEDGER_ENABLED ?= true diff --git a/app/app.go b/app/app.go index 9d880525..6e69dede 100644 --- a/app/app.go +++ b/app/app.go @@ -143,9 +143,6 @@ import ( "github.com/haqq-network/haqq/x/coinomics" coinomicskeeper "github.com/haqq-network/haqq/x/coinomics/keeper" coinomicstypes "github.com/haqq-network/haqq/x/coinomics/types" - "github.com/haqq-network/haqq/x/dao" - daokeeper "github.com/haqq-network/haqq/x/dao/keeper" - daotypes "github.com/haqq-network/haqq/x/dao/types" "github.com/haqq-network/haqq/x/epochs" epochskeeper "github.com/haqq-network/haqq/x/epochs/keeper" epochstypes "github.com/haqq-network/haqq/x/epochs/types" @@ -156,6 +153,9 @@ import ( "github.com/haqq-network/haqq/x/liquidvesting" liquidvestingkeeper "github.com/haqq-network/haqq/x/liquidvesting/keeper" liquidvestingtypes "github.com/haqq-network/haqq/x/liquidvesting/types" + "github.com/haqq-network/haqq/x/ucdao" + ucdaokeeper "github.com/haqq-network/haqq/x/ucdao/keeper" + ucdaotypes "github.com/haqq-network/haqq/x/ucdao/types" "github.com/haqq-network/haqq/x/vesting" vestingkeeper "github.com/haqq-network/haqq/x/vesting/keeper" vestingtypes "github.com/haqq-network/haqq/x/vesting/types" @@ -172,6 +172,7 @@ import ( v174 "github.com/haqq-network/haqq/app/upgrades/v1.7.4" v175 "github.com/haqq-network/haqq/app/upgrades/v1.7.5" v176 "github.com/haqq-network/haqq/app/upgrades/v1.7.6" + v177 "github.com/haqq-network/haqq/app/upgrades/v1.7.7" // NOTE: override ICS20 keeper to support IBC transfers of ERC20 tokens "github.com/haqq-network/haqq/x/ibc/transfer" @@ -249,7 +250,7 @@ var ( epochs.AppModuleBasic{}, consensus.AppModuleBasic{}, liquidvesting.AppModuleBasic{}, - dao.AppModuleBasic{}, + ucdao.AppModuleBasic{}, ) // module account permissions @@ -266,7 +267,7 @@ var ( coinomicstypes.ModuleName: {authtypes.Minter}, vestingtypes.ModuleName: nil, // Add vesting module account liquidvestingtypes.ModuleName: {authtypes.Minter, authtypes.Burner}, - daotypes.ModuleName: nil, + ucdaotypes.ModuleName: nil, } // module accounts that are allowed to receive tokens @@ -335,7 +336,7 @@ type Haqq struct { // Haqq keepers CoinomicsKeeper coinomicskeeper.Keeper - DaoKeeper daokeeper.Keeper + DaoKeeper ucdaokeeper.Keeper // the module manager mm *module.Manager @@ -409,7 +410,7 @@ func NewHaqq( // haqq keys coinomicstypes.StoreKey, liquidvestingtypes.StoreKey, - daotypes.StoreKey, + ucdaotypes.StoreKey, ) // Add the EVM transient store key @@ -559,8 +560,8 @@ func NewHaqq( app.AccountKeeper, app.BankKeeper, app.Erc20Keeper, app.VestingKeeper, ) - app.DaoKeeper = daokeeper.NewBaseKeeper( - appCodec, keys[daotypes.StoreKey], app.AccountKeeper, app.BankKeeper, authAddr, + app.DaoKeeper = ucdaokeeper.NewBaseKeeper( + appCodec, keys[ucdaotypes.StoreKey], app.AccountKeeper, app.BankKeeper, authAddr, ) epochsKeeper := epochskeeper.NewKeeper(appCodec, keys[epochstypes.StoreKey]) @@ -711,7 +712,7 @@ func NewHaqq( // Haqq app modules coinomics.NewAppModule(app.CoinomicsKeeper, app.AccountKeeper, app.StakingKeeper), - dao.NewAppModule(appCodec, app.DaoKeeper, app.GetSubspace(daotypes.ModuleName)), + ucdao.NewAppModule(appCodec, app.DaoKeeper, app.GetSubspace(ucdaotypes.ModuleName)), ) // During begin block slashing happens after distr.BeginBlocker so that @@ -749,7 +750,7 @@ func NewHaqq( coinomicstypes.ModuleName, consensusparamtypes.ModuleName, liquidvestingtypes.ModuleName, - daotypes.ModuleName, + ucdaotypes.ModuleName, ) // NOTE: fee market module must go last in order to retrieve the block gas used. @@ -786,7 +787,7 @@ func NewHaqq( coinomicstypes.ModuleName, consensusparamtypes.ModuleName, liquidvestingtypes.ModuleName, - daotypes.ModuleName, + ucdaotypes.ModuleName, ) // NOTE: The genutils module must occur after staking so that pools are @@ -826,7 +827,7 @@ func NewHaqq( coinomicstypes.ModuleName, erc20types.ModuleName, epochstypes.ModuleName, - daotypes.ModuleName, + ucdaotypes.ModuleName, // NOTE: crisis module must go at the end to check for invariants on each module crisistypes.ModuleName, consensusparamtypes.ModuleName, @@ -1189,7 +1190,7 @@ func initParamsKeeper( // haqq subspaces paramsKeeper.Subspace(coinomicstypes.ModuleName) paramsKeeper.Subspace(liquidvestingtypes.ModuleName) - paramsKeeper.Subspace(daotypes.ModuleName) + paramsKeeper.Subspace(ucdaotypes.ModuleName) return paramsKeeper } @@ -1298,6 +1299,12 @@ func (app *Haqq) setupUpgradeHandlers() { v176.CreateUpgradeHandler(app.mm, app.configurator, app.AccountKeeper, app.BankKeeper, app.StakingKeeper, app.DaoKeeper, app.LiquidVestingKeeper, app.Erc20Keeper), ) + // v1.7.7 Rename DAO module to United Contributors DAO + app.UpgradeKeeper.SetUpgradeHandler( + v177.UpgradeName, + v177.CreateUpgradeHandler(app.mm, app.configurator), + ) + // When a planned update height is reached, the old binary will panic // writing on disk the height and name of the update that triggered it // This will read that value, and execute the preparations for the upgrade. @@ -1341,7 +1348,16 @@ func (app *Haqq) setupUpgradeHandlers() { case v176.UpgradeName: storeUpgrades = &storetypes.StoreUpgrades{ Added: []string{ - daotypes.ModuleName, + ucdaotypes.ModuleOldName, + }, + } + case v177.UpgradeName: + storeUpgrades = &storetypes.StoreUpgrades{ + Renamed: []storetypes.StoreRename{ + { + OldKey: ucdaotypes.ModuleOldName, + NewKey: ucdaotypes.ModuleName, + }, }, } } diff --git a/app/upgrades/v1.7.6/handler.go b/app/upgrades/v1.7.6/handler.go index 43ead867..98bc8ed6 100644 --- a/app/upgrades/v1.7.6/handler.go +++ b/app/upgrades/v1.7.6/handler.go @@ -18,11 +18,11 @@ import ( stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" "github.com/ethereum/go-ethereum/common" - daokeeepr "github.com/haqq-network/haqq/x/dao/keeper" erc20keeper "github.com/haqq-network/haqq/x/erc20/keeper" erc20types "github.com/haqq-network/haqq/x/erc20/types" liquidvestingkeeper "github.com/haqq-network/haqq/x/liquidvesting/keeper" liquidvestingtypes "github.com/haqq-network/haqq/x/liquidvesting/types" + daokeeepr "github.com/haqq-network/haqq/x/ucdao/keeper" vestingtypes "github.com/haqq-network/haqq/x/vesting/types" ) diff --git a/app/upgrades/v1.7.6/upgrades.go b/app/upgrades/v1.7.6/upgrades.go index 64cccb3d..d9c1d336 100644 --- a/app/upgrades/v1.7.6/upgrades.go +++ b/app/upgrades/v1.7.6/upgrades.go @@ -10,9 +10,9 @@ import ( stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" - daokeeper "github.com/haqq-network/haqq/x/dao/keeper" erc20keeper "github.com/haqq-network/haqq/x/erc20/keeper" liquidvestingkeeper "github.com/haqq-network/haqq/x/liquidvesting/keeper" + daokeeper "github.com/haqq-network/haqq/x/ucdao/keeper" ) // CreateUpgradeHandler creates an SDK upgrade handler for v1.7.6 diff --git a/app/upgrades/v1.7.7/constants.go b/app/upgrades/v1.7.7/constants.go new file mode 100644 index 00000000..616ecafc --- /dev/null +++ b/app/upgrades/v1.7.7/constants.go @@ -0,0 +1,6 @@ +package v177 + +const ( + // UpgradeName is the shared upgrade plan name for mainnet and testnet + UpgradeName = "v1.7.7" +) diff --git a/app/upgrades/v1.7.7/upgrades.go b/app/upgrades/v1.7.7/upgrades.go new file mode 100644 index 00000000..c2323b8f --- /dev/null +++ b/app/upgrades/v1.7.7/upgrades.go @@ -0,0 +1,20 @@ +package v177 + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/module" + upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" +) + +// CreateUpgradeHandler creates an SDK upgrade handler for v1.7.7 +func CreateUpgradeHandler( + mm *module.Manager, + configurator module.Configurator, +) upgradetypes.UpgradeHandler { + return func(ctx sdk.Context, _ upgradetypes.Plan, vm module.VersionMap) (module.VersionMap, error) { + logger := ctx.Logger() + logger.Info("run migration v1.7.7") + + return mm.RunMigrations(ctx, configurator, vm) + } +} diff --git a/proto/haqq/dao/module/v1/module.proto b/proto/haqq/dao/module/v1/module.proto index 1723d739..6fac8e5b 100644 --- a/proto/haqq/dao/module/v1/module.proto +++ b/proto/haqq/dao/module/v1/module.proto @@ -7,7 +7,7 @@ import "cosmos/app/v1alpha1/module.proto"; // Module is the config object of the distribution module. message Module { option (cosmos.app.v1alpha1.module) = { - go_import: "github.com/haqq-network/haqq/x/dao" + go_import: "github.com/haqq-network/haqq/x/ucdao" }; // max_metadata_len defines the maximum proposal metadata length. diff --git a/proto/haqq/dao/v1/dao.proto b/proto/haqq/dao/v1/dao.proto index 6151331f..ce42f6b7 100644 --- a/proto/haqq/dao/v1/dao.proto +++ b/proto/haqq/dao/v1/dao.proto @@ -5,11 +5,11 @@ package haqq.dao.v1; import "gogoproto/gogo.proto"; import "amino/amino.proto"; -option go_package = "github.com/haqq-network/haqq/x/dao/types"; +option go_package = "github.com/haqq-network/haqq/x/ucdao/types"; // Params defines the parameters for the dao module. message Params { - option(amino.name) = "haqq/x/dao/Params"; + option(amino.name) = "haqq/x/ucdao/Params"; option(gogoproto.goproto_stringer) = false; // enable_dao is the parameter to enable the module functionality. bool enable_dao = 1; @@ -31,7 +31,7 @@ enum CollateralValueType { } message AllowedCollateral { - option(amino.name) = "haqq/x/dao/AllowedCollateral"; + option(amino.name) = "haqq/x/ucdao/AllowedCollateral"; option(gogoproto.goproto_stringer) = false; // value is the allowed collateral value. diff --git a/proto/haqq/dao/v1/genesis.proto b/proto/haqq/dao/v1/genesis.proto index 146667d6..e9810f11 100644 --- a/proto/haqq/dao/v1/genesis.proto +++ b/proto/haqq/dao/v1/genesis.proto @@ -8,7 +8,7 @@ import "cosmos_proto/cosmos.proto"; import "amino/amino.proto"; import "haqq/dao/v1/dao.proto"; -option go_package = "github.com/haqq-network/haqq/x/dao/types"; +option go_package = "github.com/haqq-network/haqq/x/ucdao/types"; // GenesisState defines the gov module's genesis state. message GenesisState { diff --git a/proto/haqq/dao/v1/query.proto b/proto/haqq/dao/v1/query.proto index 2262b4eb..b0353573 100644 --- a/proto/haqq/dao/v1/query.proto +++ b/proto/haqq/dao/v1/query.proto @@ -11,7 +11,7 @@ import "cosmos/query/v1/query.proto"; import "amino/amino.proto"; import "haqq/dao/v1/dao.proto"; -option go_package = "github.com/haqq-network/haqq/x/dao/types"; +option go_package = "github.com/haqq-network/haqq/x/ucdao/types"; // Query defines the gRPC querier service for dao module service Query { diff --git a/proto/haqq/dao/v1/tx.proto b/proto/haqq/dao/v1/tx.proto index 3a4932da..ef3cab0f 100644 --- a/proto/haqq/dao/v1/tx.proto +++ b/proto/haqq/dao/v1/tx.proto @@ -8,7 +8,7 @@ import "cosmos_proto/cosmos.proto"; import "cosmos/msg/v1/msg.proto"; import "amino/amino.proto"; -option go_package = "github.com/haqq-network/haqq/x/dao/types"; +option go_package = "github.com/haqq-network/haqq/x/ucdao/types"; // Msg defines the dao Msg service. service Msg { @@ -16,6 +16,9 @@ service Msg { // Fund defines a method to allow an account to directly fund the dao. rpc Fund(MsgFund) returns (MsgFundResponse); + + // TransferOwnership defines a method to allow an account to transfer the ownership of shares to another account. + rpc TransferOwnership(MsgTransferOwnership) returns (MsgTransferOwnershipResponse); } // MsgFund allows an account to directly fund the dao. @@ -36,3 +39,21 @@ message MsgFund { // MsgFundResponse defines the Msg/Fund response type. message MsgFundResponse {} + +// MsgTransferOwnership allows an account transfer the ownership of shares to another account. +message MsgTransferOwnership { + option (cosmos.msg.v1.signer) = "owner"; + option (amino.name) = "haqq/dao/MsgTransferOwnership"; + + option (gogoproto.equal) = false; + option (gogoproto.goproto_getters) = false; + + // owner is a current owner of the shares in dao. + string owner = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"]; + + // new_owner is a new owner of the shares in dao. + string new_owner = 2 [(cosmos_proto.scalar) = "cosmos.AddressString"]; +} + +// MsgTransferOwnershipResponse defines the Msg/TransferOwnership response type. +message MsgTransferOwnershipResponse {} \ No newline at end of file diff --git a/x/dao/keeper/integration_test.go b/x/dao/keeper/integration_test.go deleted file mode 100644 index c4bd28ad..00000000 --- a/x/dao/keeper/integration_test.go +++ /dev/null @@ -1,293 +0,0 @@ -package keeper_test - -import ( - "strings" - - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" - - sdkmath "cosmossdk.io/math" - sdk "github.com/cosmos/cosmos-sdk/types" - authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" - - "github.com/haqq-network/haqq/testutil" - "github.com/haqq-network/haqq/utils" - "github.com/haqq-network/haqq/x/dao/types" -) - -var _ = Describe("Feemarket", func() { - var ( - daoModuleAcc authtypes.ModuleAccountI - fundMsg *types.MsgFund - err error - ) - - Describe("Performing Cosmos transactions", func() { - oneHundred, _ := sdk.NewIntFromString("100000000000000000000") - oneHundredIslm := sdk.NewCoin(utils.BaseDenom, oneHundred) - oneIslm := sdk.NewInt64Coin(utils.BaseDenom, 1000000000000000000) - threeInvalid := sdk.NewInt64Coin("invalid", 3000000000000000000) - fiveLiquid1 := sdk.NewInt64Coin("aLIQUID1", 5000000000000000000) - sevenLiquid75 := sdk.NewInt64Coin("aLIQUID75", 7000000000000000000) - nineLiquidInvalid := sdk.NewInt64Coin("aLIQUID", 9000000000000000000) - gasPrice := sdkmath.NewInt(1000000000) - - Context("with invalid denom", func() { - BeforeEach(func() { - s.SetupTest() - - daoModuleAcc = s.app.AccountKeeper.GetModuleAccount(s.ctx, types.ModuleName) - - daoBalanceBefore := s.app.BankKeeper.GetBalance(s.ctx, daoModuleAcc.GetAddress(), utils.BaseDenom) - Expect(daoBalanceBefore.IsZero()).To(BeTrue(), "dao account should have no balance") - - err = testutil.FundAccount(s.ctx, s.app.BankKeeper, s.address, sdk.NewCoins(oneHundredIslm, threeInvalid, fiveLiquid1, sevenLiquid75, nineLiquidInvalid)) - s.Require().NoError(err) - - s.Commit() - }) - - Context("correct aLIQUID with invalid", func() { - It("should fail", func() { - // Check balances before TX - daoBankBalanceBefore := s.app.BankKeeper.GetBalance(s.ctx, daoModuleAcc.GetAddress(), fiveLiquid1.Denom) - Expect(daoBankBalanceBefore.IsZero()).To(BeTrue(), "dao account should have no balance") - - daoTotalBalanceBefore, err := s.queryClient.TotalBalance(s.ctx, &types.QueryTotalBalanceRequest{}) - Expect(err).To(BeNil(), "query should have succeed") - Expect(daoTotalBalanceBefore.TotalBalance.IsZero()).To(BeTrue(), "dao total balance should be empty") - - daoAddressBalanceBefore, err := s.queryClient.AllBalances(s.ctx, &types.QueryAllBalancesRequest{Address: s.address.String()}) - Expect(err).To(BeNil(), "query should have succeed") - Expect(daoAddressBalanceBefore.Balances.IsZero()).To(BeTrue(), "dao address balance should be empty") - - // TX Process - fundMsg = types.NewMsgFund( - sdk.NewCoins(threeInvalid, fiveLiquid1), - s.address, - ) - _, err = testutil.DeliverTx(s.ctx, s.app, s.priv, &gasPrice, fundMsg) - Expect(err).NotTo(BeNil(), "transaction should have failed") - Expect( - strings.Contains(err.Error(), - "denom invalid is not allowed"), - ).To(BeTrue(), err.Error()) - s.Commit() - - // Check balances after TX - daoBankBalanceAfter := s.app.BankKeeper.GetBalance(s.ctx, daoModuleAcc.GetAddress(), fiveLiquid1.Denom) - Expect(daoBankBalanceAfter.IsZero()).To(BeTrue(), "dao account should have no balance") - - daoTotalBalanceAfter, err := s.queryClient.TotalBalance(s.ctx, &types.QueryTotalBalanceRequest{}) - Expect(err).To(BeNil(), "query should have succeed") - Expect(daoTotalBalanceAfter.TotalBalance.IsZero()).To(BeTrue(), "dao total balance should be empty") - - daoAddressBalanceAfter, err := s.queryClient.AllBalances(s.ctx, &types.QueryAllBalancesRequest{Address: s.address.String()}) - Expect(err).To(BeNil(), "query should have succeed") - Expect(daoAddressBalanceAfter.Balances.IsZero()).To(BeTrue(), "dao address balance should be empty") - }) - }) - - Context("correct aISLM with invalid", func() { - It("should fail", func() { - // Check balances before TX - daoBankBalanceBefore := s.app.BankKeeper.GetBalance(s.ctx, daoModuleAcc.GetAddress(), oneIslm.Denom) - Expect(daoBankBalanceBefore.IsZero()).To(BeTrue(), "dao account should have no balance") - - daoTotalBalanceBefore, err := s.queryClient.TotalBalance(s.ctx, &types.QueryTotalBalanceRequest{}) - Expect(err).To(BeNil(), "query should have succeed") - Expect(daoTotalBalanceBefore.TotalBalance.IsZero()).To(BeTrue(), "dao total balance should be empty") - - daoAddressBalanceBefore, err := s.queryClient.AllBalances(s.ctx, &types.QueryAllBalancesRequest{Address: s.address.String()}) - Expect(err).To(BeNil(), "query should have succeed") - Expect(daoAddressBalanceBefore.Balances.IsZero()).To(BeTrue(), "dao address balance should be empty") - - // TX Process - fundMsg = types.NewMsgFund( - sdk.NewCoins(oneIslm, nineLiquidInvalid), - s.address, - ) - _, err = testutil.DeliverTx(s.ctx, s.app, s.priv, &gasPrice, fundMsg) - Expect(err).NotTo(BeNil(), "transaction should have failed") - Expect( - strings.Contains(err.Error(), - "denom aLIQUID is not allowed"), - ).To(BeTrue(), err.Error()) - s.Commit() - - // Check balances after TX - daoBankBalanceAfter := s.app.BankKeeper.GetBalance(s.ctx, daoModuleAcc.GetAddress(), oneIslm.Denom) - Expect(daoBankBalanceAfter.IsZero()).To(BeTrue(), "dao account should have no balance") - - daoTotalBalanceAfter, err := s.queryClient.TotalBalance(s.ctx, &types.QueryTotalBalanceRequest{}) - Expect(err).To(BeNil(), "query should have succeed") - Expect(daoTotalBalanceAfter.TotalBalance.IsZero()).To(BeTrue(), "dao total balance should be empty") - - daoAddressBalanceAfter, err := s.queryClient.AllBalances(s.ctx, &types.QueryAllBalancesRequest{Address: s.address.String()}) - Expect(err).To(BeNil(), "query should have succeed") - Expect(daoAddressBalanceAfter.Balances.IsZero()).To(BeTrue(), "dao address balance should be empty") - }) - }) - }) - - Context("with correct denoms", func() { - BeforeEach(func() { - s.SetupTest() - - err = testutil.FundAccount(s.ctx, s.app.BankKeeper, s.address, sdk.NewCoins(oneHundredIslm, threeInvalid, fiveLiquid1, sevenLiquid75, nineLiquidInvalid)) - s.Require().NoError(err) - - s.Commit() - }) - - Context("correct standalone aLIQUID", func() { - It("should pass", func() { - // Check balances before TX - daoBankBalanceBefore := s.app.BankKeeper.GetBalance(s.ctx, daoModuleAcc.GetAddress(), sevenLiquid75.Denom) - Expect(daoBankBalanceBefore.IsZero()).To(BeTrue(), "dao account should have no balance") - - daoTotalBalanceBefore, err := s.queryClient.TotalBalance(s.ctx, &types.QueryTotalBalanceRequest{}) - Expect(err).To(BeNil(), "query should have succeed") - Expect(daoTotalBalanceBefore.TotalBalance.IsZero()).To(BeTrue(), "dao total balance should be empty") - - daoAddressBalanceBefore, err := s.queryClient.AllBalances(s.ctx, &types.QueryAllBalancesRequest{Address: s.address.String()}) - Expect(err).To(BeNil(), "query should have succeed") - Expect(daoAddressBalanceBefore.Balances.IsZero()).To(BeTrue(), "dao address balance should be empty") - - // TX Process - fundMsg = types.NewMsgFund( - sdk.NewCoins(sevenLiquid75), - s.address, - ) - _, err = testutil.DeliverTx(s.ctx, s.app, s.priv, &gasPrice, fundMsg) - Expect(err).To(BeNil(), "transaction should have succeed") - s.Commit() - - // Check balances after TX - daoBankBalanceAfter := s.app.BankKeeper.GetBalance(s.ctx, daoModuleAcc.GetAddress(), sevenLiquid75.Denom) - Expect(daoBankBalanceAfter.Amount.String()).To(Equal(sevenLiquid75.Amount.String()), "dao account should have received the funds") - - daoTotalBalanceAfter, err := s.queryClient.TotalBalance(s.ctx, &types.QueryTotalBalanceRequest{}) - Expect(err).To(BeNil(), "query should have succeed") - ok, amount := daoTotalBalanceAfter.TotalBalance.Find(sevenLiquid75.Denom) - Expect(ok).To(BeTrue(), "dao total balance should have received the funds") - Expect(amount.String()).To(Equal(sevenLiquid75.String()), "dao total balance should have received the funds") - - daoAddressBalanceAfter, err := s.queryClient.AllBalances(s.ctx, &types.QueryAllBalancesRequest{Address: s.address.String()}) - Expect(err).To(BeNil(), "query should have succeed") - okAcc, amountAcc := daoAddressBalanceAfter.Balances.Find(sevenLiquid75.Denom) - Expect(okAcc).To(BeTrue(), "dao address balance should have received the funds") - Expect(amountAcc.String()).To(Equal(sevenLiquid75.String()), "dao address balance should have received the funds") - }) - }) - - Context("correct standalone aISLM", func() { - It("should pass", func() { - // Check balances before TX - daoBankBalanceBefore := s.app.BankKeeper.GetBalance(s.ctx, daoModuleAcc.GetAddress(), oneIslm.Denom) - Expect(daoBankBalanceBefore.IsZero()).To(BeTrue(), "dao account should have no balance") - - daoTotalBalanceBefore, err := s.queryClient.TotalBalance(s.ctx, &types.QueryTotalBalanceRequest{}) - Expect(err).To(BeNil(), "query should have succeed") - Expect(daoTotalBalanceBefore.TotalBalance.IsZero()).To(BeTrue(), "dao total balance should be empty") - - daoAddressBalanceBefore, err := s.queryClient.AllBalances(s.ctx, &types.QueryAllBalancesRequest{Address: s.address.String()}) - Expect(err).To(BeNil(), "query should have succeed") - Expect(daoAddressBalanceBefore.Balances.IsZero()).To(BeTrue(), "dao address balance should be empty") - - // TX Process - fundMsg = types.NewMsgFund( - sdk.NewCoins(oneIslm), - s.address, - ) - _, err = testutil.DeliverTx(s.ctx, s.app, s.priv, &gasPrice, fundMsg) - Expect(err).To(BeNil(), "transaction should have succeed") - s.Commit() - - // Check balances after TX - daoBankBalanceAfter := s.app.BankKeeper.GetBalance(s.ctx, daoModuleAcc.GetAddress(), oneIslm.Denom) - Expect(daoBankBalanceAfter.Amount.String()).To(Equal(oneIslm.Amount.String()), "dao account should have received the funds") - - daoTotalBalanceAfter, err := s.queryClient.TotalBalance(s.ctx, &types.QueryTotalBalanceRequest{}) - Expect(err).To(BeNil(), "query should have succeed") - ok, amount := daoTotalBalanceAfter.TotalBalance.Find(oneIslm.Denom) - Expect(ok).To(BeTrue(), "dao total balance should have received the funds") - Expect(amount.String()).To(Equal(oneIslm.String()), "dao total balance should have received the funds") - - daoAddressBalanceAfter, err := s.queryClient.AllBalances(s.ctx, &types.QueryAllBalancesRequest{Address: s.address.String()}) - Expect(err).To(BeNil(), "query should have succeed") - okAcc, amountAcc := daoAddressBalanceAfter.Balances.Find(oneIslm.Denom) - Expect(okAcc).To(BeTrue(), "dao address balance should have received the funds") - Expect(amountAcc.String()).To(Equal(oneIslm.String()), "dao address balance should have received the funds") - }) - }) - - Context("correct aISLM and aLIQUID", func() { - It("should pass", func() { - // Check balances before TX - daoBankIslmBalanceBefore := s.app.BankKeeper.GetBalance(s.ctx, daoModuleAcc.GetAddress(), oneIslm.Denom) - Expect(daoBankIslmBalanceBefore.IsZero()).To(BeTrue(), "dao account should have no balance") - - daoTotalIslmBalanceBefore, err := s.queryClient.TotalBalance(s.ctx, &types.QueryTotalBalanceRequest{}) - Expect(err).To(BeNil(), "query should have succeed") - Expect(daoTotalIslmBalanceBefore.TotalBalance.IsZero()).To(BeTrue(), "dao total balance should be empty") - - daoAddressIslmBalanceBefore, err := s.queryClient.AllBalances(s.ctx, &types.QueryAllBalancesRequest{Address: s.address.String()}) - Expect(err).To(BeNil(), "query should have succeed") - Expect(daoAddressIslmBalanceBefore.Balances.IsZero()).To(BeTrue(), "dao address balance should be empty") - - daoBankLiquidBalanceBefore := s.app.BankKeeper.GetBalance(s.ctx, daoModuleAcc.GetAddress(), fiveLiquid1.Denom) - Expect(daoBankLiquidBalanceBefore.IsZero()).To(BeTrue(), "dao account should have no balance") - - daoTotalLiquidBalanceBefore, err := s.queryClient.TotalBalance(s.ctx, &types.QueryTotalBalanceRequest{}) - Expect(err).To(BeNil(), "query should have succeed") - Expect(daoTotalLiquidBalanceBefore.TotalBalance.IsZero()).To(BeTrue(), "dao total balance should be empty") - - daoAddressLiquidBalanceBefore, err := s.queryClient.AllBalances(s.ctx, &types.QueryAllBalancesRequest{Address: s.address.String()}) - Expect(err).To(BeNil(), "query should have succeed") - Expect(daoAddressLiquidBalanceBefore.Balances.IsZero()).To(BeTrue(), "dao address balance should be empty") - - // TX Process - fundMsg = types.NewMsgFund( - sdk.NewCoins(oneIslm, fiveLiquid1), - s.address, - ) - _, err = testutil.DeliverTx(s.ctx, s.app, s.priv, &gasPrice, fundMsg) - Expect(err).To(BeNil(), "transaction should have succeed") - s.Commit() - - // Check balances after TX - daoBankIslmBalanceAfter := s.app.BankKeeper.GetBalance(s.ctx, daoModuleAcc.GetAddress(), oneIslm.Denom) - Expect(daoBankIslmBalanceAfter.Amount.String()).To(Equal(oneIslm.Amount.String()), "dao account should have received the funds") - - daoTotalIslmBalanceAfter, err := s.queryClient.TotalBalance(s.ctx, &types.QueryTotalBalanceRequest{}) - Expect(err).To(BeNil(), "query should have succeed") - ok, amount := daoTotalIslmBalanceAfter.TotalBalance.Find(oneIslm.Denom) - Expect(ok).To(BeTrue(), "dao total balance should have received the funds") - Expect(amount.String()).To(Equal(oneIslm.String()), "dao total balance should have received the funds") - - daoAddressIslmBalanceAfter, err := s.queryClient.AllBalances(s.ctx, &types.QueryAllBalancesRequest{Address: s.address.String()}) - Expect(err).To(BeNil(), "query should have succeed") - okAcc, amountAcc := daoAddressIslmBalanceAfter.Balances.Find(oneIslm.Denom) - Expect(okAcc).To(BeTrue(), "dao address balance should have received the funds") - Expect(amountAcc.String()).To(Equal(oneIslm.String()), "dao address balance should have received the funds") - - daoBankLiquidBalanceAfter := s.app.BankKeeper.GetBalance(s.ctx, daoModuleAcc.GetAddress(), fiveLiquid1.Denom) - Expect(daoBankLiquidBalanceAfter.Amount.String()).To(Equal(fiveLiquid1.Amount.String()), "dao account should have received the funds") - - daoTotalLiquidBalanceAfter, err := s.queryClient.TotalBalance(s.ctx, &types.QueryTotalBalanceRequest{}) - Expect(err).To(BeNil(), "query should have succeed") - ok, amountLiq := daoTotalLiquidBalanceAfter.TotalBalance.Find(fiveLiquid1.Denom) - Expect(ok).To(BeTrue(), "dao total balance should have received the funds") - Expect(amountLiq.String()).To(Equal(fiveLiquid1.String()), "dao total balance should have received the funds") - - daoAddressLiquidBalanceAfter, err := s.queryClient.AllBalances(s.ctx, &types.QueryAllBalancesRequest{Address: s.address.String()}) - Expect(err).To(BeNil(), "query should have succeed") - okAcc, amountLiqAcc := daoAddressLiquidBalanceAfter.Balances.Find(fiveLiquid1.Denom) - Expect(okAcc).To(BeTrue(), "dao address balance should have received the funds") - Expect(amountLiqAcc.String()).To(Equal(fiveLiquid1.String()), "dao address balance should have received the funds") - }) - }) - }) - }) -}) diff --git a/x/dao/client/cli/query.go b/x/ucdao/client/cli/query.go similarity index 94% rename from x/dao/client/cli/query.go rename to x/ucdao/client/cli/query.go index e1ac6a3b..9087bd5c 100644 --- a/x/dao/client/cli/query.go +++ b/x/ucdao/client/cli/query.go @@ -11,7 +11,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/version" - "github.com/haqq-network/haqq/x/dao/types" + "github.com/haqq-network/haqq/x/ucdao/types" ) const ( @@ -41,7 +41,7 @@ func GetQueryCmd() *cobra.Command { func GetBalancesCmd() *cobra.Command { cmd := &cobra.Command{ Use: "balances [address]", - Short: "Query for account balances in the DAO by address", + Short: "Query for account balances in the United Contributors DAO by address", Long: strings.TrimSpace( fmt.Sprintf(`Query the total balance of an account or of a specific denomination. @@ -110,7 +110,7 @@ Example: func GetCmdQueryTotalBalance() *cobra.Command { cmd := &cobra.Command{ Use: "total-balance", - Short: "Query the total balances of coins in the DAO", + Short: "Query the total balances of coins in the United Contributors DAO", Args: cobra.NoArgs, Long: strings.TrimSpace( fmt.Sprintf(`Query total balances of coins that are held by accounts in the DAO. diff --git a/x/dao/client/cli/tx.go b/x/ucdao/client/cli/tx.go similarity index 55% rename from x/dao/client/cli/tx.go rename to x/ucdao/client/cli/tx.go index 1e2269af..809c350f 100644 --- a/x/dao/client/cli/tx.go +++ b/x/ucdao/client/cli/tx.go @@ -12,7 +12,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/version" - "github.com/haqq-network/haqq/x/dao/types" + "github.com/haqq-network/haqq/x/ucdao/types" ) // Transaction flags for the x/distribution module @@ -29,7 +29,7 @@ const ( func NewTxCmd() *cobra.Command { distTxCmd := &cobra.Command{ Use: types.ModuleName, - Short: "Distribution transactions subcommands", + Short: "United Contributors DAO transactions subcommands", DisableFlagParsing: true, SuggestionsMinimumDistance: 2, RunE: client.ValidateCmd, @@ -37,6 +37,7 @@ func NewTxCmd() *cobra.Command { distTxCmd.AddCommand( NewFundDAOCmd(), + NewTransferOwnershipCmd(), ) return distTxCmd @@ -47,7 +48,7 @@ func NewFundDAOCmd() *cobra.Command { cmd := &cobra.Command{ Use: "fund [amount]", Args: cobra.ExactArgs(1), - Short: "Funds the DAO with the specified amount", + Short: "Funds the United Contributors DAO with the specified amount", Long: strings.TrimSpace( fmt.Sprintf(`Funds the dao with the specified amount @@ -78,3 +79,44 @@ $ %s tx %s fund 100aISLM --from mykey return cmd } + +// NewTransferOwnershipCmd returns a CLI command handler for creating a MsgTransferOwnership transaction. +func NewTransferOwnershipCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "transfer-ownership [from_address] [to_address]", + Args: cobra.ExactArgs(2), + Short: "Transfer all United Contributors DAO shares from one address to another", + Long: strings.TrimSpace( + fmt.Sprintf(`Transfer all DAO shares from one address to another + +Example: +$ %s tx %s transfer-ownership haqq1tjdjfavsy956d25hvhs3p0nw9a7pfghqm0up92 haqq1hdr0lhv75vesvtndlh78ck4cez6esz8u2lk0hq --from mykey +`, + version.AppName, types.ModuleName, + ), + ), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + owner, err := sdk.AccAddressFromBech32(args[0]) + if err != nil { + return err + } + newOwner, err := sdk.AccAddressFromBech32(args[1]) + if err != nil { + return err + } + + msg := types.NewMsgTransferOwnership(owner, newOwner) + + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) + }, + } + + flags.AddTxFlagsToCmd(cmd) + + return cmd +} diff --git a/x/dao/exported/exported.go b/x/ucdao/exported/exported.go similarity index 100% rename from x/dao/exported/exported.go rename to x/ucdao/exported/exported.go diff --git a/x/dao/keeper/account_balances.go b/x/ucdao/keeper/account_balances.go similarity index 94% rename from x/dao/keeper/account_balances.go rename to x/ucdao/keeper/account_balances.go index 9276174d..97c4882a 100644 --- a/x/dao/keeper/account_balances.go +++ b/x/ucdao/keeper/account_balances.go @@ -8,7 +8,7 @@ import ( "github.com/cosmos/cosmos-sdk/types/address" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - "github.com/haqq-network/haqq/x/dao/types" + "github.com/haqq-network/haqq/x/ucdao/types" ) // GetBalance returns the balance of a specific denomination for a given account @@ -51,6 +51,17 @@ func (k BaseKeeper) IterateAccountBalances(ctx sdk.Context, addr sdk.AccAddress, } } +func (k BaseKeeper) GetAccountBalances(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins { + balances := sdk.NewCoins() + + k.IterateAccountBalances(ctx, addr, func(balance sdk.Coin) bool { + balances = balances.Add(balance) + return false + }) + + return balances +} + // IterateAllBalances iterates over all the balances of all accounts and // denominations that are provided to a callback. If true is returned from the // callback, iteration is halted. diff --git a/x/dao/keeper/genesis.go b/x/ucdao/keeper/genesis.go similarity index 98% rename from x/dao/keeper/genesis.go rename to x/ucdao/keeper/genesis.go index 24e03603..d6f3ddcc 100644 --- a/x/dao/keeper/genesis.go +++ b/x/ucdao/keeper/genesis.go @@ -8,7 +8,7 @@ import ( "github.com/cosmos/cosmos-sdk/types/address" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - "github.com/haqq-network/haqq/x/dao/types" + "github.com/haqq-network/haqq/x/ucdao/types" ) // InitGenesis initializes the bank module's state from a given genesis state. diff --git a/x/dao/keeper/grpc_query.go b/x/ucdao/keeper/grpc_query.go similarity index 98% rename from x/dao/keeper/grpc_query.go rename to x/ucdao/keeper/grpc_query.go index 910d9b0a..0446d987 100644 --- a/x/dao/keeper/grpc_query.go +++ b/x/ucdao/keeper/grpc_query.go @@ -8,7 +8,7 @@ import ( "google.golang.org/grpc/codes" "google.golang.org/grpc/status" - "github.com/haqq-network/haqq/x/dao/types" + "github.com/haqq-network/haqq/x/ucdao/types" ) var _ types.QueryServer = BaseKeeper{} diff --git a/x/ucdao/keeper/integration_test.go b/x/ucdao/keeper/integration_test.go new file mode 100644 index 00000000..57a5ddb4 --- /dev/null +++ b/x/ucdao/keeper/integration_test.go @@ -0,0 +1,617 @@ +package keeper_test + +import ( + "strings" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + + sdkmath "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + + "github.com/haqq-network/haqq/crypto/ethsecp256k1" + "github.com/haqq-network/haqq/testutil" + "github.com/haqq-network/haqq/utils" + "github.com/haqq-network/haqq/x/ucdao/types" +) + +var _ = Describe("United Contributors DAO", func() { + var ( + daoModuleAcc authtypes.ModuleAccountI + fundMsg *types.MsgFund + transferOwnershipMsg *types.MsgTransferOwnership + err error + ) + + oneHundred, _ := sdk.NewIntFromString("100000000000000000000") + oneHundredIslm := sdk.NewCoin(utils.BaseDenom, oneHundred) + oneIslm := sdk.NewInt64Coin(utils.BaseDenom, 1000000000000000000) + threeInvalid := sdk.NewInt64Coin("invalid", 3000000000000000000) + fiveLiquid1 := sdk.NewInt64Coin("aLIQUID1", 5000000000000000000) + sevenLiquid75 := sdk.NewInt64Coin("aLIQUID75", 7000000000000000000) + nineLiquidInvalid := sdk.NewInt64Coin("aLIQUID", 9000000000000000000) + gasPrice := sdkmath.NewInt(1000000000) + + Describe("Fund transactions", func() { + Context("with invalid denom", func() { + BeforeEach(func() { + s.SetupTest() + + daoModuleAcc = s.app.AccountKeeper.GetModuleAccount(s.ctx, types.ModuleName) + + daoBalanceBefore := s.app.BankKeeper.GetBalance(s.ctx, daoModuleAcc.GetAddress(), utils.BaseDenom) + Expect(daoBalanceBefore.IsZero()).To(BeTrue(), "dao account should have no balance") + + err = testutil.FundAccount(s.ctx, s.app.BankKeeper, s.address, sdk.NewCoins(oneHundredIslm, threeInvalid, fiveLiquid1, sevenLiquid75, nineLiquidInvalid)) + s.Require().NoError(err) + + s.Commit() + }) + + Context("correct aLIQUID with invalid", func() { + It("should fail", func() { + // Check balances before TX + daoBankBalanceBefore := s.app.BankKeeper.GetBalance(s.ctx, daoModuleAcc.GetAddress(), fiveLiquid1.Denom) + Expect(daoBankBalanceBefore.IsZero()).To(BeTrue(), "dao account should have no balance") + + daoTotalBalanceBefore, err := s.queryClient.TotalBalance(s.ctx, &types.QueryTotalBalanceRequest{}) + Expect(err).To(BeNil(), "query should have succeed") + Expect(daoTotalBalanceBefore.TotalBalance.IsZero()).To(BeTrue(), "dao total balance should be empty") + + daoAddressBalanceBefore, err := s.queryClient.AllBalances(s.ctx, &types.QueryAllBalancesRequest{Address: s.address.String()}) + Expect(err).To(BeNil(), "query should have succeed") + Expect(daoAddressBalanceBefore.Balances.IsZero()).To(BeTrue(), "dao address balance should be empty") + + // TX Process + fundMsg = types.NewMsgFund( + sdk.NewCoins(threeInvalid, fiveLiquid1), + s.address, + ) + _, err = testutil.DeliverTx(s.ctx, s.app, s.priv, &gasPrice, fundMsg) + Expect(err).NotTo(BeNil(), "transaction should have failed") + Expect( + strings.Contains(err.Error(), + "denom invalid is not allowed"), + ).To(BeTrue(), err.Error()) + s.Commit() + + // Check balances after TX + daoBankBalanceAfter := s.app.BankKeeper.GetBalance(s.ctx, daoModuleAcc.GetAddress(), fiveLiquid1.Denom) + Expect(daoBankBalanceAfter.IsZero()).To(BeTrue(), "dao account should have no balance") + + daoTotalBalanceAfter, err := s.queryClient.TotalBalance(s.ctx, &types.QueryTotalBalanceRequest{}) + Expect(err).To(BeNil(), "query should have succeed") + Expect(daoTotalBalanceAfter.TotalBalance.IsZero()).To(BeTrue(), "dao total balance should be empty") + + daoAddressBalanceAfter, err := s.queryClient.AllBalances(s.ctx, &types.QueryAllBalancesRequest{Address: s.address.String()}) + Expect(err).To(BeNil(), "query should have succeed") + Expect(daoAddressBalanceAfter.Balances.IsZero()).To(BeTrue(), "dao address balance should be empty") + }) + }) + + Context("correct aISLM with invalid", func() { + It("should fail", func() { + // Check balances before TX + daoBankBalanceBefore := s.app.BankKeeper.GetBalance(s.ctx, daoModuleAcc.GetAddress(), oneIslm.Denom) + Expect(daoBankBalanceBefore.IsZero()).To(BeTrue(), "dao account should have no balance") + + daoTotalBalanceBefore, err := s.queryClient.TotalBalance(s.ctx, &types.QueryTotalBalanceRequest{}) + Expect(err).To(BeNil(), "query should have succeed") + Expect(daoTotalBalanceBefore.TotalBalance.IsZero()).To(BeTrue(), "dao total balance should be empty") + + daoAddressBalanceBefore, err := s.queryClient.AllBalances(s.ctx, &types.QueryAllBalancesRequest{Address: s.address.String()}) + Expect(err).To(BeNil(), "query should have succeed") + Expect(daoAddressBalanceBefore.Balances.IsZero()).To(BeTrue(), "dao address balance should be empty") + + // TX Process + fundMsg = types.NewMsgFund( + sdk.NewCoins(oneIslm, nineLiquidInvalid), + s.address, + ) + _, err = testutil.DeliverTx(s.ctx, s.app, s.priv, &gasPrice, fundMsg) + Expect(err).NotTo(BeNil(), "transaction should have failed") + Expect( + strings.Contains(err.Error(), + "denom aLIQUID is not allowed"), + ).To(BeTrue(), err.Error()) + s.Commit() + + // Check balances after TX + daoBankBalanceAfter := s.app.BankKeeper.GetBalance(s.ctx, daoModuleAcc.GetAddress(), oneIslm.Denom) + Expect(daoBankBalanceAfter.IsZero()).To(BeTrue(), "dao account should have no balance") + + daoTotalBalanceAfter, err := s.queryClient.TotalBalance(s.ctx, &types.QueryTotalBalanceRequest{}) + Expect(err).To(BeNil(), "query should have succeed") + Expect(daoTotalBalanceAfter.TotalBalance.IsZero()).To(BeTrue(), "dao total balance should be empty") + + daoAddressBalanceAfter, err := s.queryClient.AllBalances(s.ctx, &types.QueryAllBalancesRequest{Address: s.address.String()}) + Expect(err).To(BeNil(), "query should have succeed") + Expect(daoAddressBalanceAfter.Balances.IsZero()).To(BeTrue(), "dao address balance should be empty") + }) + }) + }) + + Context("with correct denoms", func() { + BeforeEach(func() { + s.SetupTest() + + err = testutil.FundAccount(s.ctx, s.app.BankKeeper, s.address, sdk.NewCoins(oneHundredIslm, threeInvalid, fiveLiquid1, sevenLiquid75, nineLiquidInvalid)) + s.Require().NoError(err) + + s.Commit() + }) + + Context("correct standalone aLIQUID", func() { + It("should pass", func() { + // Check balances before TX + daoBankBalanceBefore := s.app.BankKeeper.GetBalance(s.ctx, daoModuleAcc.GetAddress(), sevenLiquid75.Denom) + Expect(daoBankBalanceBefore.IsZero()).To(BeTrue(), "dao account should have no balance") + + daoTotalBalanceBefore, err := s.queryClient.TotalBalance(s.ctx, &types.QueryTotalBalanceRequest{}) + Expect(err).To(BeNil(), "query should have succeed") + Expect(daoTotalBalanceBefore.TotalBalance.IsZero()).To(BeTrue(), "dao total balance should be empty") + + daoAddressBalanceBefore, err := s.queryClient.AllBalances(s.ctx, &types.QueryAllBalancesRequest{Address: s.address.String()}) + Expect(err).To(BeNil(), "query should have succeed") + Expect(daoAddressBalanceBefore.Balances.IsZero()).To(BeTrue(), "dao address balance should be empty") + + // TX Process + fundMsg = types.NewMsgFund( + sdk.NewCoins(sevenLiquid75), + s.address, + ) + _, err = testutil.DeliverTx(s.ctx, s.app, s.priv, &gasPrice, fundMsg) + Expect(err).To(BeNil(), "transaction should have succeed") + s.Commit() + + // Check balances after TX + daoBankBalanceAfter := s.app.BankKeeper.GetBalance(s.ctx, daoModuleAcc.GetAddress(), sevenLiquid75.Denom) + Expect(daoBankBalanceAfter.Amount.String()).To(Equal(sevenLiquid75.Amount.String()), "dao account should have received the funds") + + daoTotalBalanceAfter, err := s.queryClient.TotalBalance(s.ctx, &types.QueryTotalBalanceRequest{}) + Expect(err).To(BeNil(), "query should have succeed") + ok, amount := daoTotalBalanceAfter.TotalBalance.Find(sevenLiquid75.Denom) + Expect(ok).To(BeTrue(), "dao total balance should have received the funds") + Expect(amount.String()).To(Equal(sevenLiquid75.String()), "dao total balance should have received the funds") + + daoAddressBalanceAfter, err := s.queryClient.AllBalances(s.ctx, &types.QueryAllBalancesRequest{Address: s.address.String()}) + Expect(err).To(BeNil(), "query should have succeed") + okAcc, amountAcc := daoAddressBalanceAfter.Balances.Find(sevenLiquid75.Denom) + Expect(okAcc).To(BeTrue(), "dao address balance should have received the funds") + Expect(amountAcc.String()).To(Equal(sevenLiquid75.String()), "dao address balance should have received the funds") + }) + }) + + Context("correct standalone aISLM", func() { + It("should pass", func() { + // Check balances before TX + daoBankBalanceBefore := s.app.BankKeeper.GetBalance(s.ctx, daoModuleAcc.GetAddress(), oneIslm.Denom) + Expect(daoBankBalanceBefore.IsZero()).To(BeTrue(), "dao account should have no balance") + + daoTotalBalanceBefore, err := s.queryClient.TotalBalance(s.ctx, &types.QueryTotalBalanceRequest{}) + Expect(err).To(BeNil(), "query should have succeed") + Expect(daoTotalBalanceBefore.TotalBalance.IsZero()).To(BeTrue(), "dao total balance should be empty") + + daoAddressBalanceBefore, err := s.queryClient.AllBalances(s.ctx, &types.QueryAllBalancesRequest{Address: s.address.String()}) + Expect(err).To(BeNil(), "query should have succeed") + Expect(daoAddressBalanceBefore.Balances.IsZero()).To(BeTrue(), "dao address balance should be empty") + + // TX Process + fundMsg = types.NewMsgFund( + sdk.NewCoins(oneIslm), + s.address, + ) + _, err = testutil.DeliverTx(s.ctx, s.app, s.priv, &gasPrice, fundMsg) + Expect(err).To(BeNil(), "transaction should have succeed") + s.Commit() + + // Check balances after TX + daoBankBalanceAfter := s.app.BankKeeper.GetBalance(s.ctx, daoModuleAcc.GetAddress(), oneIslm.Denom) + Expect(daoBankBalanceAfter.Amount.String()).To(Equal(oneIslm.Amount.String()), "dao account should have received the funds") + + daoTotalBalanceAfter, err := s.queryClient.TotalBalance(s.ctx, &types.QueryTotalBalanceRequest{}) + Expect(err).To(BeNil(), "query should have succeed") + ok, amount := daoTotalBalanceAfter.TotalBalance.Find(oneIslm.Denom) + Expect(ok).To(BeTrue(), "dao total balance should have received the funds") + Expect(amount.String()).To(Equal(oneIslm.String()), "dao total balance should have received the funds") + + daoAddressBalanceAfter, err := s.queryClient.AllBalances(s.ctx, &types.QueryAllBalancesRequest{Address: s.address.String()}) + Expect(err).To(BeNil(), "query should have succeed") + okAcc, amountAcc := daoAddressBalanceAfter.Balances.Find(oneIslm.Denom) + Expect(okAcc).To(BeTrue(), "dao address balance should have received the funds") + Expect(amountAcc.String()).To(Equal(oneIslm.String()), "dao address balance should have received the funds") + }) + }) + + Context("correct aISLM and aLIQUID", func() { + It("should pass", func() { + // Check balances before TX + daoBankIslmBalanceBefore := s.app.BankKeeper.GetBalance(s.ctx, daoModuleAcc.GetAddress(), oneIslm.Denom) + Expect(daoBankIslmBalanceBefore.IsZero()).To(BeTrue(), "dao account should have no balance") + + daoTotalIslmBalanceBefore, err := s.queryClient.TotalBalance(s.ctx, &types.QueryTotalBalanceRequest{}) + Expect(err).To(BeNil(), "query should have succeed") + Expect(daoTotalIslmBalanceBefore.TotalBalance.IsZero()).To(BeTrue(), "dao total balance should be empty") + + daoAddressIslmBalanceBefore, err := s.queryClient.AllBalances(s.ctx, &types.QueryAllBalancesRequest{Address: s.address.String()}) + Expect(err).To(BeNil(), "query should have succeed") + Expect(daoAddressIslmBalanceBefore.Balances.IsZero()).To(BeTrue(), "dao address balance should be empty") + + daoBankLiquidBalanceBefore := s.app.BankKeeper.GetBalance(s.ctx, daoModuleAcc.GetAddress(), fiveLiquid1.Denom) + Expect(daoBankLiquidBalanceBefore.IsZero()).To(BeTrue(), "dao account should have no balance") + + daoTotalLiquidBalanceBefore, err := s.queryClient.TotalBalance(s.ctx, &types.QueryTotalBalanceRequest{}) + Expect(err).To(BeNil(), "query should have succeed") + Expect(daoTotalLiquidBalanceBefore.TotalBalance.IsZero()).To(BeTrue(), "dao total balance should be empty") + + daoAddressLiquidBalanceBefore, err := s.queryClient.AllBalances(s.ctx, &types.QueryAllBalancesRequest{Address: s.address.String()}) + Expect(err).To(BeNil(), "query should have succeed") + Expect(daoAddressLiquidBalanceBefore.Balances.IsZero()).To(BeTrue(), "dao address balance should be empty") + + // TX Process + fundMsg = types.NewMsgFund( + sdk.NewCoins(oneIslm, fiveLiquid1), + s.address, + ) + _, err = testutil.DeliverTx(s.ctx, s.app, s.priv, &gasPrice, fundMsg) + Expect(err).To(BeNil(), "transaction should have succeed") + s.Commit() + + // Check balances after TX + daoBankIslmBalanceAfter := s.app.BankKeeper.GetBalance(s.ctx, daoModuleAcc.GetAddress(), oneIslm.Denom) + Expect(daoBankIslmBalanceAfter.Amount.String()).To(Equal(oneIslm.Amount.String()), "dao account should have received the funds") + + daoTotalIslmBalanceAfter, err := s.queryClient.TotalBalance(s.ctx, &types.QueryTotalBalanceRequest{}) + Expect(err).To(BeNil(), "query should have succeed") + ok, amount := daoTotalIslmBalanceAfter.TotalBalance.Find(oneIslm.Denom) + Expect(ok).To(BeTrue(), "dao total balance should have received the funds") + Expect(amount.String()).To(Equal(oneIslm.String()), "dao total balance should have received the funds") + + daoAddressIslmBalanceAfter, err := s.queryClient.AllBalances(s.ctx, &types.QueryAllBalancesRequest{Address: s.address.String()}) + Expect(err).To(BeNil(), "query should have succeed") + okAcc, amountAcc := daoAddressIslmBalanceAfter.Balances.Find(oneIslm.Denom) + Expect(okAcc).To(BeTrue(), "dao address balance should have received the funds") + Expect(amountAcc.String()).To(Equal(oneIslm.String()), "dao address balance should have received the funds") + + daoBankLiquidBalanceAfter := s.app.BankKeeper.GetBalance(s.ctx, daoModuleAcc.GetAddress(), fiveLiquid1.Denom) + Expect(daoBankLiquidBalanceAfter.Amount.String()).To(Equal(fiveLiquid1.Amount.String()), "dao account should have received the funds") + + daoTotalLiquidBalanceAfter, err := s.queryClient.TotalBalance(s.ctx, &types.QueryTotalBalanceRequest{}) + Expect(err).To(BeNil(), "query should have succeed") + ok, amountLiq := daoTotalLiquidBalanceAfter.TotalBalance.Find(fiveLiquid1.Denom) + Expect(ok).To(BeTrue(), "dao total balance should have received the funds") + Expect(amountLiq.String()).To(Equal(fiveLiquid1.String()), "dao total balance should have received the funds") + + daoAddressLiquidBalanceAfter, err := s.queryClient.AllBalances(s.ctx, &types.QueryAllBalancesRequest{Address: s.address.String()}) + Expect(err).To(BeNil(), "query should have succeed") + okAcc, amountLiqAcc := daoAddressLiquidBalanceAfter.Balances.Find(fiveLiquid1.Denom) + Expect(okAcc).To(BeTrue(), "dao address balance should have received the funds") + Expect(amountLiqAcc.String()).To(Equal(fiveLiquid1.String()), "dao address balance should have received the funds") + }) + }) + }) + }) + + Describe("Transfer Ownership transactions", func() { + newOwnerPriv, err := ethsecp256k1.GenerateKey() + newOwnerAddr := sdk.AccAddress(newOwnerPriv.PubKey().Address().Bytes()) + + Context("basic validation", func() { + BeforeEach(func() { + s.SetupTest() + + err = testutil.FundAccount(s.ctx, s.app.BankKeeper, s.address, sdk.NewCoins(oneHundredIslm)) + s.Require().NoError(err) + + s.Commit() + }) + + It("should fail - invalid owner address", func() { + // TX Process + transferOwnershipMsg = &types.MsgTransferOwnership{ + Owner: "haqq1", + NewOwner: newOwnerAddr.String(), + } + + _, err = testutil.DeliverTx(s.ctx, s.app, s.priv, &gasPrice, transferOwnershipMsg) + Expect(err).NotTo(BeNil(), "transaction should fail") + Expect(err.Error()).To(ContainSubstring("invalid owner address")) + s.Commit() + }) + + It("should fail - invalid new owner address", func() { + // TX Process + transferOwnershipMsg = &types.MsgTransferOwnership{ + Owner: s.address.String(), + NewOwner: "haqq1", + } + + _, err = testutil.DeliverTx(s.ctx, s.app, s.priv, &gasPrice, transferOwnershipMsg) + Expect(err).NotTo(BeNil(), "transaction should fail") + Expect(err.Error()).To(ContainSubstring("invalid new owner address")) + s.Commit() + }) + }) + + Context("with non-member as owner", func() { + BeforeEach(func() { + s.SetupTest() + + err = testutil.FundAccount(s.ctx, s.app.BankKeeper, s.address, sdk.NewCoins(oneHundredIslm)) + s.Require().NoError(err) + + s.Commit() + }) + + It("should fail - not eligible", func() { + daoTotalBalanceBefore, err := s.queryClient.TotalBalance(s.ctx, &types.QueryTotalBalanceRequest{}) + Expect(err).To(BeNil(), "query should have succeed") + Expect(daoTotalBalanceBefore.TotalBalance.IsZero()).To(BeTrue(), "dao total balance should be empty") + + daoAddressBalanceBefore, err := s.queryClient.AllBalances(s.ctx, &types.QueryAllBalancesRequest{Address: s.address.String()}) + Expect(err).To(BeNil(), "query should have succeed") + Expect(daoAddressBalanceBefore.Balances.IsZero()).To(BeTrue(), "dao address balance should be empty") + + // TX Process + transferOwnershipMsg = types.NewMsgTransferOwnership(s.address, newOwnerAddr) + + _, err = testutil.DeliverTx(s.ctx, s.app, s.priv, &gasPrice, transferOwnershipMsg) + Expect(err).NotTo(BeNil(), "transaction should fail") + Expect(err.Error()).To(ContainSubstring("not eligible"), "error message should be correct") + s.Commit() + }) + }) + + Context("with member as owner and non-member as new owner", func() { + BeforeEach(func() { + s.SetupTest() + + err = testutil.FundAccount(s.ctx, s.app.BankKeeper, s.address, sdk.NewCoins(oneHundredIslm, fiveLiquid1)) + s.Require().NoError(err) + + s.Commit() + }) + + It("successfully transferred", func() { + daoModuleAddressBankBalanceBeforeFund := s.app.BankKeeper.GetAllBalances(s.ctx, daoModuleAcc.GetAddress()) + Expect(daoModuleAddressBankBalanceBeforeFund.IsZero()).To(BeTrue(), "dao module account bank balance should be empty") + + daoTotalBalanceBeforeFund, err := s.queryClient.TotalBalance(s.ctx, &types.QueryTotalBalanceRequest{}) + Expect(err).To(BeNil(), "query should have succeed") + Expect(daoTotalBalanceBeforeFund.TotalBalance.IsZero()).To(BeTrue(), "dao total balance should be empty") + + daoOwnerAddressBalanceBeforeFund, err := s.queryClient.AllBalances(s.ctx, &types.QueryAllBalancesRequest{Address: s.address.String()}) + Expect(err).To(BeNil(), "query should have succeed") + Expect(daoOwnerAddressBalanceBeforeFund.Balances.IsZero()).To(BeTrue(), "dao module address balance should be empty") + + // Fund TX Process + fundMsg = types.NewMsgFund( + sdk.NewCoins(oneIslm, fiveLiquid1), + s.address, + ) + _, err = testutil.DeliverTx(s.ctx, s.app, s.priv, &gasPrice, fundMsg) + Expect(err).To(BeNil(), "transaction should have succeed") + s.Commit() + + // Check balances after funding TX + daoModuleAddressBankBalanceAfterFundIslm := s.app.BankKeeper.GetBalance(s.ctx, daoModuleAcc.GetAddress(), oneIslm.Denom) + Expect(daoModuleAddressBankBalanceAfterFundIslm.Amount.String()).To(Equal(oneIslm.Amount.String()), "dao account should have received the funds") + daoModuleAddressBankBalanceAfterFundLiquid := s.app.BankKeeper.GetBalance(s.ctx, daoModuleAcc.GetAddress(), fiveLiquid1.Denom) + Expect(daoModuleAddressBankBalanceAfterFundLiquid.Amount.String()).To(Equal(fiveLiquid1.Amount.String()), "dao account should have received the funds") + + daoTotalBalanceAfterFund, err := s.queryClient.TotalBalance(s.ctx, &types.QueryTotalBalanceRequest{}) + Expect(err).To(BeNil(), "query should have succeed") + Expect(daoTotalBalanceAfterFund.TotalBalance.IsZero()).To(BeFalse(), "dao total balance should not be empty") + ok, islmAmountAfterFund := daoTotalBalanceAfterFund.TotalBalance.Find(oneIslm.Denom) + Expect(ok).To(BeTrue(), "dao total balance should have received the funds") + Expect(islmAmountAfterFund.String()).To(Equal(oneIslm.String()), "dao total balance should have received the funds") + ok, liquidAmountAfterFund := daoTotalBalanceAfterFund.TotalBalance.Find(fiveLiquid1.Denom) + Expect(ok).To(BeTrue(), "dao total balance should have received the funds") + Expect(liquidAmountAfterFund.String()).To(Equal(fiveLiquid1.String()), "dao total balance should have received the funds") + + daoOwnerAddressAllBalancesAfterFund, err := s.queryClient.AllBalances(s.ctx, &types.QueryAllBalancesRequest{Address: s.address.String()}) + Expect(err).To(BeNil(), "query should have succeed") + Expect(daoOwnerAddressAllBalancesAfterFund.Balances.IsZero()).To(BeFalse(), "dao account balance should not be empty") + okAcc, islmAccAmount := daoOwnerAddressAllBalancesAfterFund.Balances.Find(oneIslm.Denom) + Expect(okAcc).To(BeTrue(), "dao address balance should have received the funds") + Expect(islmAccAmount.String()).To(Equal(oneIslm.String()), "dao address balance should have received the funds") + okAcc, liquidAccAmount := daoOwnerAddressAllBalancesAfterFund.Balances.Find(fiveLiquid1.Denom) + Expect(okAcc).To(BeTrue(), "dao address balance should have received the funds") + Expect(liquidAccAmount.String()).To(Equal(fiveLiquid1.String()), "dao address balance should have received the funds") + + daoOwnerAddressIslmBalanceAfterFund, err := s.queryClient.Balance(s.ctx, &types.QueryBalanceRequest{Address: s.address.String(), Denom: oneIslm.Denom}) + Expect(err).To(BeNil(), "query should have succeed") + Expect(daoOwnerAddressIslmBalanceAfterFund.Balance.String()).To(Equal(oneIslm.String()), "dao address balance should have received the funds") + daoOwnerAddressLiquidBalanceAfterFund, err := s.queryClient.Balance(s.ctx, &types.QueryBalanceRequest{Address: s.address.String(), Denom: fiveLiquid1.Denom}) + Expect(err).To(BeNil(), "query should have succeed") + Expect(daoOwnerAddressLiquidBalanceAfterFund.Balance.String()).To(Equal(fiveLiquid1.String()), "dao address balance should have received the funds") + + // Store new owner address balances before transfer ownership + daoNewOwnerAddressAllBalancesBeforeTransfer, err := s.queryClient.AllBalances(s.ctx, &types.QueryAllBalancesRequest{Address: newOwnerAddr.String()}) + Expect(err).To(BeNil(), "query should have succeed") + Expect(daoNewOwnerAddressAllBalancesBeforeTransfer.Balances.IsZero()).To(BeTrue(), "dao new owner address balance should be empty") + + // Transfer TX Process + transferOwnershipMsg = types.NewMsgTransferOwnership(s.address, newOwnerAddr) + _, err = testutil.DeliverTx(s.ctx, s.app, s.priv, &gasPrice, transferOwnershipMsg) + Expect(err).To(BeNil(), "transaction should succeed") + s.Commit() + + // Checks after transfer ownership + // Module bank balance shouldn't change + daoModuleAddressBankBalanceAfterTransferIslm := s.app.BankKeeper.GetBalance(s.ctx, daoModuleAcc.GetAddress(), oneIslm.Denom) + Expect(daoModuleAddressBankBalanceAfterTransferIslm.Amount.String()).To(Equal(daoModuleAddressBankBalanceAfterFundIslm.Amount.String())) + daoModuleAddressBankBalanceAfterTransferLiquid := s.app.BankKeeper.GetBalance(s.ctx, daoModuleAcc.GetAddress(), fiveLiquid1.Denom) + Expect(daoModuleAddressBankBalanceAfterTransferLiquid.Amount.String()).To(Equal(daoModuleAddressBankBalanceAfterFundLiquid.Amount.String())) + + // Module internal total balance shouldn't change + daoTotalBalanceAfterTransfer, err := s.queryClient.TotalBalance(s.ctx, &types.QueryTotalBalanceRequest{}) + Expect(err).To(BeNil()) + Expect(daoTotalBalanceAfterTransfer.TotalBalance.IsZero()).To(BeFalse()) + ok, islmAmountAfterTransfer := daoTotalBalanceAfterTransfer.TotalBalance.Find(oneIslm.Denom) + Expect(ok).To(BeTrue()) + Expect(islmAmountAfterTransfer.String()).To(Equal(islmAmountAfterFund.String())) + ok, liquidAmountAfterTransfer := daoTotalBalanceAfterTransfer.TotalBalance.Find(fiveLiquid1.Denom) + Expect(ok).To(BeTrue()) + Expect(liquidAmountAfterTransfer.String()).To(Equal(liquidAmountAfterFund.String())) + + // Old owner internal dao balance should become empty + daoOwnerAddressAllBalancesAfterTransfer, err := s.queryClient.AllBalances(s.ctx, &types.QueryAllBalancesRequest{Address: s.address.String()}) + Expect(err).To(BeNil()) + Expect(daoOwnerAddressAllBalancesAfterTransfer.Balances.IsZero()).To(BeTrue()) + + // All tokens should be transferred to new owner + daoNewOwnerAddressAllBalancesAfterTransfer, err := s.queryClient.AllBalances(s.ctx, &types.QueryAllBalancesRequest{Address: newOwnerAddr.String()}) + Expect(err).To(BeNil()) + Expect(daoNewOwnerAddressAllBalancesAfterTransfer.Balances.IsZero()).To(BeFalse()) + okNewAcc, islmNewAccAmount := daoNewOwnerAddressAllBalancesAfterTransfer.Balances.Find(oneIslm.Denom) + Expect(okNewAcc).To(BeTrue()) + Expect(islmNewAccAmount.String()).To(Equal(oneIslm.String())) + okNewAcc, liquidNewAccAmount := daoNewOwnerAddressAllBalancesAfterTransfer.Balances.Find(fiveLiquid1.Denom) + Expect(okNewAcc).To(BeTrue()) + Expect(liquidNewAccAmount.String()).To(Equal(fiveLiquid1.String())) + daoNewOwnerAddressIslmBalanceAfterTransfer, err := s.queryClient.Balance(s.ctx, &types.QueryBalanceRequest{Address: newOwnerAddr.String(), Denom: oneIslm.Denom}) + Expect(err).To(BeNil()) + Expect(daoNewOwnerAddressIslmBalanceAfterTransfer.Balance.String()).To(Equal(oneIslm.String())) + daoNewOwnerAddressLiquidBalanceAfterTransfer, err := s.queryClient.Balance(s.ctx, &types.QueryBalanceRequest{Address: newOwnerAddr.String(), Denom: fiveLiquid1.Denom}) + Expect(err).To(BeNil()) + Expect(daoNewOwnerAddressLiquidBalanceAfterTransfer.Balance.String()).To(Equal(fiveLiquid1.String())) + }) + }) + + Context("with both owner and new owner as members", func() { + BeforeEach(func() { + s.SetupTest() + + // Fund owner account + err = testutil.FundAccount(s.ctx, s.app.BankKeeper, s.address, sdk.NewCoins(oneHundredIslm, fiveLiquid1)) + s.Require().NoError(err) + + // Fund new owner account + err = testutil.FundAccount(s.ctx, s.app.BankKeeper, newOwnerAddr, sdk.NewCoins(oneHundredIslm)) + s.Require().NoError(err) + + s.Commit() + }) + + It("successfully transferred", func() { + daoModuleAddressBankBalanceBeforeFund := s.app.BankKeeper.GetAllBalances(s.ctx, daoModuleAcc.GetAddress()) + Expect(daoModuleAddressBankBalanceBeforeFund.IsZero()).To(BeTrue(), "dao module account bank balance should be empty") + + daoTotalBalanceBeforeFund, err := s.queryClient.TotalBalance(s.ctx, &types.QueryTotalBalanceRequest{}) + Expect(err).To(BeNil(), "query should have succeed") + Expect(daoTotalBalanceBeforeFund.TotalBalance.IsZero()).To(BeTrue(), "dao total balance should be empty") + + daoOwnerAddressBalanceBeforeFund, err := s.queryClient.AllBalances(s.ctx, &types.QueryAllBalancesRequest{Address: s.address.String()}) + Expect(err).To(BeNil(), "query should have succeed") + Expect(daoOwnerAddressBalanceBeforeFund.Balances.IsZero()).To(BeTrue(), "dao module address balance should be empty") + + // Fund by owner TX Process + fundMsg = types.NewMsgFund( + sdk.NewCoins(oneIslm, fiveLiquid1), + s.address, + ) + _, err = testutil.DeliverTx(s.ctx, s.app, s.priv, &gasPrice, fundMsg) + Expect(err).To(BeNil(), "transaction should have succeed") + s.Commit() + + // Fund by new owner TX Process + twoIslm := oneIslm.Add(oneIslm) + fundMsg = types.NewMsgFund( + sdk.NewCoins(twoIslm), + newOwnerAddr, + ) + _, err = testutil.DeliverTx(s.ctx, s.app, newOwnerPriv, &gasPrice, fundMsg) + Expect(err).To(BeNil(), "transaction should have succeed") + s.Commit() + + // Check balances after funding TX + daoModuleAddressBankBalanceAfterFundIslm := s.app.BankKeeper.GetBalance(s.ctx, daoModuleAcc.GetAddress(), oneIslm.Denom) + Expect(daoModuleAddressBankBalanceAfterFundIslm.Amount.String()).To(Equal(oneIslm.Amount.Add(twoIslm.Amount).String())) + daoModuleAddressBankBalanceAfterFundLiquid := s.app.BankKeeper.GetBalance(s.ctx, daoModuleAcc.GetAddress(), fiveLiquid1.Denom) + Expect(daoModuleAddressBankBalanceAfterFundLiquid.Amount.String()).To(Equal(fiveLiquid1.Amount.String())) + + daoTotalBalanceAfterFund, err := s.queryClient.TotalBalance(s.ctx, &types.QueryTotalBalanceRequest{}) + Expect(err).To(BeNil()) + Expect(daoTotalBalanceAfterFund.TotalBalance.IsZero()).To(BeFalse()) + ok, islmAmountAfterFund := daoTotalBalanceAfterFund.TotalBalance.Find(oneIslm.Denom) + Expect(ok).To(BeTrue()) + Expect(islmAmountAfterFund.String()).To(Equal(oneIslm.Add(twoIslm).String())) + ok, liquidAmountAfterFund := daoTotalBalanceAfterFund.TotalBalance.Find(fiveLiquid1.Denom) + Expect(ok).To(BeTrue()) + Expect(liquidAmountAfterFund.String()).To(Equal(fiveLiquid1.String())) + + daoOwnerAddressAllBalancesAfterFund, err := s.queryClient.AllBalances(s.ctx, &types.QueryAllBalancesRequest{Address: s.address.String()}) + Expect(err).To(BeNil()) + Expect(daoOwnerAddressAllBalancesAfterFund.Balances.IsZero()).To(BeFalse()) + okAcc, islmAccAmount := daoOwnerAddressAllBalancesAfterFund.Balances.Find(oneIslm.Denom) + Expect(okAcc).To(BeTrue()) + Expect(islmAccAmount.String()).To(Equal(oneIslm.String())) + okAcc, liquidAccAmount := daoOwnerAddressAllBalancesAfterFund.Balances.Find(fiveLiquid1.Denom) + Expect(okAcc).To(BeTrue()) + Expect(liquidAccAmount.String()).To(Equal(fiveLiquid1.String())) + + daoOwnerAddressIslmBalanceAfterFund, err := s.queryClient.Balance(s.ctx, &types.QueryBalanceRequest{Address: s.address.String(), Denom: oneIslm.Denom}) + Expect(err).To(BeNil()) + Expect(daoOwnerAddressIslmBalanceAfterFund.Balance.String()).To(Equal(oneIslm.String())) + daoOwnerAddressLiquidBalanceAfterFund, err := s.queryClient.Balance(s.ctx, &types.QueryBalanceRequest{Address: s.address.String(), Denom: fiveLiquid1.Denom}) + Expect(err).To(BeNil()) + Expect(daoOwnerAddressLiquidBalanceAfterFund.Balance.String()).To(Equal(fiveLiquid1.String())) + + daoNewOwnerAddressAllBalancesAfterFund, err := s.queryClient.AllBalances(s.ctx, &types.QueryAllBalancesRequest{Address: newOwnerAddr.String()}) + Expect(err).To(BeNil()) + Expect(daoNewOwnerAddressAllBalancesAfterFund.Balances.IsZero()).To(BeFalse()) + okNewAcc, islmNewAccAmount := daoNewOwnerAddressAllBalancesAfterFund.Balances.Find(twoIslm.Denom) + Expect(okNewAcc).To(BeTrue()) + Expect(islmNewAccAmount.String()).To(Equal(twoIslm.String())) + + // Transfer TX Process + transferOwnershipMsg = types.NewMsgTransferOwnership(s.address, newOwnerAddr) + _, err = testutil.DeliverTx(s.ctx, s.app, s.priv, &gasPrice, transferOwnershipMsg) + Expect(err).To(BeNil(), "transaction should succeed") + s.Commit() + + // Checks after transfer ownership + // Module bank balance shouldn't change + daoModuleAddressBankBalanceAfterTransferIslm := s.app.BankKeeper.GetBalance(s.ctx, daoModuleAcc.GetAddress(), oneIslm.Denom) + Expect(daoModuleAddressBankBalanceAfterTransferIslm.Amount.String()).To(Equal(daoModuleAddressBankBalanceAfterFundIslm.Amount.String())) + daoModuleAddressBankBalanceAfterTransferLiquid := s.app.BankKeeper.GetBalance(s.ctx, daoModuleAcc.GetAddress(), fiveLiquid1.Denom) + Expect(daoModuleAddressBankBalanceAfterTransferLiquid.Amount.String()).To(Equal(daoModuleAddressBankBalanceAfterFundLiquid.Amount.String())) + + // Module internal total balance shouldn't change + daoTotalBalanceAfterTransfer, err := s.queryClient.TotalBalance(s.ctx, &types.QueryTotalBalanceRequest{}) + Expect(err).To(BeNil()) + Expect(daoTotalBalanceAfterTransfer.TotalBalance.IsZero()).To(BeFalse()) + ok, islmAmountAfterTransfer := daoTotalBalanceAfterTransfer.TotalBalance.Find(oneIslm.Denom) + Expect(ok).To(BeTrue()) + Expect(islmAmountAfterTransfer.String()).To(Equal(islmAmountAfterFund.String())) + ok, liquidAmountAfterTransfer := daoTotalBalanceAfterTransfer.TotalBalance.Find(fiveLiquid1.Denom) + Expect(ok).To(BeTrue()) + Expect(liquidAmountAfterTransfer.String()).To(Equal(liquidAmountAfterFund.String())) + + // Old owner internal dao balance should become empty + daoOwnerAddressAllBalancesAfterTransfer, err := s.queryClient.AllBalances(s.ctx, &types.QueryAllBalancesRequest{Address: s.address.String()}) + Expect(err).To(BeNil()) + Expect(daoOwnerAddressAllBalancesAfterTransfer.Balances.IsZero()).To(BeTrue()) + + // All tokens should be transferred to new owner + daoNewOwnerAddressAllBalancesAfterTransfer, err := s.queryClient.AllBalances(s.ctx, &types.QueryAllBalancesRequest{Address: newOwnerAddr.String()}) + Expect(err).To(BeNil()) + Expect(daoNewOwnerAddressAllBalancesAfterTransfer.Balances.IsZero()).To(BeFalse()) + okNewAcc, islmNewAccAmount = daoNewOwnerAddressAllBalancesAfterTransfer.Balances.Find(oneIslm.Denom) + Expect(okNewAcc).To(BeTrue()) + Expect(islmNewAccAmount.String()).To(Equal(oneIslm.Add(twoIslm).String())) + okNewAcc, liquidNewAccAmount := daoNewOwnerAddressAllBalancesAfterTransfer.Balances.Find(fiveLiquid1.Denom) + Expect(okNewAcc).To(BeTrue()) + Expect(liquidNewAccAmount.String()).To(Equal(fiveLiquid1.String())) + daoNewOwnerAddressIslmBalanceAfterTransfer, err := s.queryClient.Balance(s.ctx, &types.QueryBalanceRequest{Address: newOwnerAddr.String(), Denom: oneIslm.Denom}) + Expect(err).To(BeNil()) + Expect(daoNewOwnerAddressIslmBalanceAfterTransfer.Balance.String()).To(Equal(oneIslm.Add(twoIslm).String())) + daoNewOwnerAddressLiquidBalanceAfterTransfer, err := s.queryClient.Balance(s.ctx, &types.QueryBalanceRequest{Address: newOwnerAddr.String(), Denom: fiveLiquid1.Denom}) + Expect(err).To(BeNil()) + Expect(daoNewOwnerAddressLiquidBalanceAfterTransfer.Balance.String()).To(Equal(fiveLiquid1.String())) + }) + }) + }) +}) diff --git a/x/dao/keeper/keeper.go b/x/ucdao/keeper/keeper.go similarity index 82% rename from x/dao/keeper/keeper.go rename to x/ucdao/keeper/keeper.go index 58efdaea..3076c6ae 100644 --- a/x/dao/keeper/keeper.go +++ b/x/ucdao/keeper/keeper.go @@ -12,7 +12,7 @@ import ( "github.com/cosmos/cosmos-sdk/types/query" "github.com/haqq-network/haqq/utils" - "github.com/haqq-network/haqq/x/dao/types" + "github.com/haqq-network/haqq/x/ucdao/types" ) var _ Keeper = (*BaseKeeper)(nil) @@ -29,10 +29,12 @@ type Keeper interface { GetBalance(ctx sdk.Context, addr sdk.AccAddress, denom string) sdk.Coin HasBalance(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coin) bool IterateAccountBalances(ctx sdk.Context, addr sdk.AccAddress, cb func(sdk.Coin) bool) + GetAccountBalances(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins IterateAllBalances(ctx sdk.Context, cb func(sdk.AccAddress, sdk.Coin) bool) GetAccountsBalances(ctx sdk.Context) []types.Balance Fund(ctx sdk.Context, amount sdk.Coins, sender sdk.AccAddress) error + TransferOwnership(ctx sdk.Context, owner, newOwner sdk.AccAddress) error // grpc query endpoints Balance(ctx context.Context, req *types.QueryBalanceRequest) (*types.QueryBalanceResponse, error) @@ -109,6 +111,32 @@ func (k BaseKeeper) Fund(ctx sdk.Context, amount sdk.Coins, sender sdk.AccAddres return nil } +func (k BaseKeeper) TransferOwnership(ctx sdk.Context, owner, newOwner sdk.AccAddress) error { + if !k.IsModuleEnabled(ctx) { + return types.ErrModuleDisabled + } + + coins := k.GetAccountBalances(ctx, owner) + if coins.IsZero() { + return types.ErrNotEligible + } + + // Add coins to new owner + err := k.addCoinsToAccount(ctx, newOwner, coins) + if err != nil { + return err + } + + // Remove coins from old owner + for _, coin := range coins { + if err := k.setBalance(ctx, owner, sdk.NewCoin(coin.Denom, sdk.ZeroInt())); err != nil { + return err + } + } + + return nil +} + // Logger returns a module-specific logger. func (k BaseKeeper) Logger(ctx sdk.Context) log.Logger { return ctx.Logger().With("module", "x/"+types.ModuleName) diff --git a/x/dao/keeper/msg_server.go b/x/ucdao/keeper/msg_server.go similarity index 56% rename from x/dao/keeper/msg_server.go rename to x/ucdao/keeper/msg_server.go index a700cc79..bbad2a26 100644 --- a/x/dao/keeper/msg_server.go +++ b/x/ucdao/keeper/msg_server.go @@ -5,7 +5,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/haqq-network/haqq/x/dao/types" + "github.com/haqq-network/haqq/x/ucdao/types" ) type msgServer struct { @@ -33,3 +33,23 @@ func (k msgServer) Fund(goCtx context.Context, msg *types.MsgFund) (*types.MsgFu return &types.MsgFundResponse{}, nil } + +func (k msgServer) TransferOwnership(goCtx context.Context, msg *types.MsgTransferOwnership) (*types.MsgTransferOwnershipResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + + owner, err := sdk.AccAddressFromBech32(msg.Owner) + if err != nil { + return nil, err + } + + newOwner, err := sdk.AccAddressFromBech32(msg.NewOwner) + if err != nil { + return nil, err + } + + if err := k.Keeper.TransferOwnership(ctx, owner, newOwner); err != nil { + return nil, err + } + + return &types.MsgTransferOwnershipResponse{}, nil +} diff --git a/x/dao/keeper/params.go b/x/ucdao/keeper/params.go similarity index 94% rename from x/dao/keeper/params.go rename to x/ucdao/keeper/params.go index 6854af0f..af6e18ca 100644 --- a/x/dao/keeper/params.go +++ b/x/ucdao/keeper/params.go @@ -3,7 +3,7 @@ package keeper import ( sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/haqq-network/haqq/x/dao/types" + "github.com/haqq-network/haqq/x/ucdao/types" ) // GetParams returns the total set of dao parameters. diff --git a/x/dao/keeper/setup_test.go b/x/ucdao/keeper/setup_test.go similarity index 98% rename from x/dao/keeper/setup_test.go rename to x/ucdao/keeper/setup_test.go index 077c86ad..875f84b6 100644 --- a/x/dao/keeper/setup_test.go +++ b/x/ucdao/keeper/setup_test.go @@ -29,8 +29,8 @@ import ( utiltx "github.com/haqq-network/haqq/testutil/tx" haqqtypes "github.com/haqq-network/haqq/types" "github.com/haqq-network/haqq/utils" - "github.com/haqq-network/haqq/x/dao/types" evmtypes "github.com/haqq-network/haqq/x/evm/types" + "github.com/haqq-network/haqq/x/ucdao/types" ) type KeeperTestSuite struct { diff --git a/x/dao/keeper/store.go b/x/ucdao/keeper/store.go similarity index 93% rename from x/dao/keeper/store.go rename to x/ucdao/keeper/store.go index 4e81a844..2e545384 100644 --- a/x/dao/keeper/store.go +++ b/x/ucdao/keeper/store.go @@ -4,7 +4,7 @@ import ( "github.com/cosmos/cosmos-sdk/store/prefix" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/haqq-network/haqq/x/dao/types" + "github.com/haqq-network/haqq/x/ucdao/types" ) // getAccountStore gets the account store of the given address. diff --git a/x/dao/keeper/total_balance.go b/x/ucdao/keeper/total_balance.go similarity index 98% rename from x/dao/keeper/total_balance.go rename to x/ucdao/keeper/total_balance.go index a88bf2d4..83c9b623 100644 --- a/x/dao/keeper/total_balance.go +++ b/x/ucdao/keeper/total_balance.go @@ -9,7 +9,7 @@ import ( "github.com/cosmos/cosmos-sdk/types/query" "github.com/haqq-network/haqq/utils" - "github.com/haqq-network/haqq/x/dao/types" + "github.com/haqq-network/haqq/x/ucdao/types" ) // GetTotalBalance get the global total balance of dao module diff --git a/x/dao/keeper/utils.go b/x/ucdao/keeper/utils.go similarity index 100% rename from x/dao/keeper/utils.go rename to x/ucdao/keeper/utils.go diff --git a/x/dao/module.go b/x/ucdao/module.go similarity index 96% rename from x/dao/module.go rename to x/ucdao/module.go index 03f3965f..3d322a89 100644 --- a/x/dao/module.go +++ b/x/ucdao/module.go @@ -1,4 +1,4 @@ -package dao +package ucdao import ( "context" @@ -23,10 +23,10 @@ import ( gwruntime "github.com/grpc-ecosystem/grpc-gateway/runtime" "github.com/spf13/cobra" - "github.com/haqq-network/haqq/x/dao/client/cli" - "github.com/haqq-network/haqq/x/dao/exported" - "github.com/haqq-network/haqq/x/dao/keeper" - "github.com/haqq-network/haqq/x/dao/types" + "github.com/haqq-network/haqq/x/ucdao/client/cli" + "github.com/haqq-network/haqq/x/ucdao/exported" + "github.com/haqq-network/haqq/x/ucdao/keeper" + "github.com/haqq-network/haqq/x/ucdao/types" ) // ConsensusVersion defines the current x/dao module consensus version. diff --git a/x/dao/spec/README.md b/x/ucdao/spec/README.md similarity index 100% rename from x/dao/spec/README.md rename to x/ucdao/spec/README.md diff --git a/x/dao/types/balance.go b/x/ucdao/types/balance.go similarity index 98% rename from x/dao/types/balance.go rename to x/ucdao/types/balance.go index eba50741..7ec654ed 100644 --- a/x/dao/types/balance.go +++ b/x/ucdao/types/balance.go @@ -8,7 +8,7 @@ import ( "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/haqq-network/haqq/x/dao/exported" + "github.com/haqq-network/haqq/x/ucdao/exported" ) var _ exported.GenesisBalance = (*Balance)(nil) diff --git a/x/dao/types/codec.go b/x/ucdao/types/codec.go similarity index 91% rename from x/dao/types/codec.go rename to x/ucdao/types/codec.go index 4bea78e0..c89ba9c0 100644 --- a/x/dao/types/codec.go +++ b/x/ucdao/types/codec.go @@ -18,9 +18,9 @@ var ( // RegisterLegacyAminoCodec registers all the necessary types and interfaces for the dao module. func RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { - legacy.RegisterAminoMsg(cdc, &MsgFund{}, "haqq/dao/MsgFund") + legacy.RegisterAminoMsg(cdc, &MsgFund{}, "haqq/ucdao/MsgFund") - cdc.RegisterConcrete(Params{}, "haqq/x/dao/Params", nil) + cdc.RegisterConcrete(Params{}, "haqq/x/ucdao/Params", nil) } // RegisterInterfaces registers the interfaces types with the Interface Registry. diff --git a/x/dao/types/dao.pb.go b/x/ucdao/types/dao.pb.go similarity index 100% rename from x/dao/types/dao.pb.go rename to x/ucdao/types/dao.pb.go diff --git a/x/dao/types/errors.go b/x/ucdao/types/errors.go similarity index 81% rename from x/dao/types/errors.go rename to x/ucdao/types/errors.go index 59311228..84191aef 100644 --- a/x/dao/types/errors.go +++ b/x/ucdao/types/errors.go @@ -6,4 +6,5 @@ var ( ErrInvalidKey = sdkerrors.Register(ModuleName, 1, "invalid key") ErrModuleDisabled = sdkerrors.Register(ModuleName, 2, "module is disabled") ErrInvalidDenom = sdkerrors.Register(ModuleName, 3, "invalid denom") + ErrNotEligible = sdkerrors.Register(ModuleName, 4, "not eligible") ) diff --git a/x/dao/types/expected_keepers.go b/x/ucdao/types/expected_keepers.go similarity index 100% rename from x/dao/types/expected_keepers.go rename to x/ucdao/types/expected_keepers.go diff --git a/x/dao/types/genesis.go b/x/ucdao/types/genesis.go similarity index 100% rename from x/dao/types/genesis.go rename to x/ucdao/types/genesis.go diff --git a/x/dao/types/genesis.pb.go b/x/ucdao/types/genesis.pb.go similarity index 100% rename from x/dao/types/genesis.pb.go rename to x/ucdao/types/genesis.pb.go diff --git a/x/dao/types/keys.go b/x/ucdao/types/keys.go similarity index 94% rename from x/dao/types/keys.go rename to x/ucdao/types/keys.go index dff384dd..b6e4850d 100644 --- a/x/dao/types/keys.go +++ b/x/ucdao/types/keys.go @@ -8,7 +8,10 @@ import ( const ( // ModuleName is the module name constant used in many places - ModuleName = "dao" + ModuleName = "ucdao" + + // ModuleOldName is the module old name constant used for store migration + ModuleOldName = "dao" // StoreKey is the store key string for distribution StoreKey = ModuleName diff --git a/x/dao/types/msg.go b/x/ucdao/types/msg.go similarity index 50% rename from x/dao/types/msg.go rename to x/ucdao/types/msg.go index 5495e790..18604c58 100644 --- a/x/dao/types/msg.go +++ b/x/ucdao/types/msg.go @@ -7,12 +7,14 @@ import ( ) const ( - TypeMsgFund = "fund_dao" + TypeMsgFund = "fund_dao" + TypeMsgTransferOwnership = "transfer_ownership" ) // Verify interface at compile time var ( _ sdk.Msg = (*MsgFund)(nil) + _ sdk.Msg = (*MsgTransferOwnership)(nil) ) // NewMsgFund returns a new MsgFund with a sender and @@ -58,3 +60,42 @@ func (msg MsgFund) ValidateBasic() error { func (m *AllowedCollateral) String() string { return proto.CompactTextString(m) } + +// NewMsgTransferOwnership returns a new MsgTransferOwnership with an old and new owner addresses. +func NewMsgTransferOwnership(owner, newOwner sdk.AccAddress) *MsgTransferOwnership { + return &MsgTransferOwnership{ + Owner: owner.String(), + NewOwner: newOwner.String(), + } +} + +// Route returns the MsgTransferOwnership message route. +func (msg MsgTransferOwnership) Route() string { return ModuleName } + +// Type returns the MsgTransferOwnership message type. +func (msg MsgTransferOwnership) Type() string { return TypeMsgTransferOwnership } + +// GetSigners returns the signer addresses that are expected to sign the result +// of GetSignBytes. +func (msg MsgTransferOwnership) GetSigners() []sdk.AccAddress { + owner, _ := sdk.AccAddressFromBech32(msg.Owner) + return []sdk.AccAddress{owner} +} + +// GetSignBytes returns the raw bytes for a MsgTransferOwnership message that +// the expected signer needs to sign. +func (msg MsgTransferOwnership) GetSignBytes() []byte { + bz := ModuleCdc.MustMarshalJSON(&msg) + return sdk.MustSortJSON(bz) +} + +// ValidateBasic performs basic MsgTransferOwnership message validation. +func (msg MsgTransferOwnership) ValidateBasic() error { + if _, err := sdk.AccAddressFromBech32(msg.Owner); err != nil { + return sdkerrors.ErrInvalidAddress.Wrapf("invalid owner address: %s", err) + } + if _, err := sdk.AccAddressFromBech32(msg.NewOwner); err != nil { + return sdkerrors.ErrInvalidAddress.Wrapf("invalid new owner address: %s", err) + } + return nil +} diff --git a/x/dao/types/params.go b/x/ucdao/types/params.go similarity index 100% rename from x/dao/types/params.go rename to x/ucdao/types/params.go diff --git a/x/dao/types/querier.go b/x/ucdao/types/querier.go similarity index 100% rename from x/dao/types/querier.go rename to x/ucdao/types/querier.go diff --git a/x/dao/types/query.pb.go b/x/ucdao/types/query.pb.go similarity index 100% rename from x/dao/types/query.pb.go rename to x/ucdao/types/query.pb.go diff --git a/x/dao/types/query.pb.gw.go b/x/ucdao/types/query.pb.gw.go similarity index 100% rename from x/dao/types/query.pb.gw.go rename to x/ucdao/types/query.pb.gw.go diff --git a/x/dao/types/tx.pb.go b/x/ucdao/types/tx.pb.go similarity index 51% rename from x/dao/types/tx.pb.go rename to x/ucdao/types/tx.pb.go index c8d0eefa..6cd64344 100644 --- a/x/dao/types/tx.pb.go +++ b/x/ucdao/types/tx.pb.go @@ -109,40 +109,126 @@ func (m *MsgFundResponse) XXX_DiscardUnknown() { var xxx_messageInfo_MsgFundResponse proto.InternalMessageInfo +// MsgTransferOwnership allows an account transfer the ownership of shares to another account. +type MsgTransferOwnership struct { + // owner is a current owner of the shares in dao. + Owner string `protobuf:"bytes,1,opt,name=owner,proto3" json:"owner,omitempty"` + // new_owner is a new owner of the shares in dao. + NewOwner string `protobuf:"bytes,2,opt,name=new_owner,json=newOwner,proto3" json:"new_owner,omitempty"` +} + +func (m *MsgTransferOwnership) Reset() { *m = MsgTransferOwnership{} } +func (m *MsgTransferOwnership) String() string { return proto.CompactTextString(m) } +func (*MsgTransferOwnership) ProtoMessage() {} +func (*MsgTransferOwnership) Descriptor() ([]byte, []int) { + return fileDescriptor_32cf174189eaa32b, []int{2} +} +func (m *MsgTransferOwnership) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgTransferOwnership) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgTransferOwnership.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 *MsgTransferOwnership) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgTransferOwnership.Merge(m, src) +} +func (m *MsgTransferOwnership) XXX_Size() int { + return m.Size() +} +func (m *MsgTransferOwnership) XXX_DiscardUnknown() { + xxx_messageInfo_MsgTransferOwnership.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgTransferOwnership proto.InternalMessageInfo + +// MsgTransferOwnershipResponse defines the Msg/TransferOwnership response type. +type MsgTransferOwnershipResponse struct { +} + +func (m *MsgTransferOwnershipResponse) Reset() { *m = MsgTransferOwnershipResponse{} } +func (m *MsgTransferOwnershipResponse) String() string { return proto.CompactTextString(m) } +func (*MsgTransferOwnershipResponse) ProtoMessage() {} +func (*MsgTransferOwnershipResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_32cf174189eaa32b, []int{3} +} +func (m *MsgTransferOwnershipResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgTransferOwnershipResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgTransferOwnershipResponse.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 *MsgTransferOwnershipResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgTransferOwnershipResponse.Merge(m, src) +} +func (m *MsgTransferOwnershipResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgTransferOwnershipResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgTransferOwnershipResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgTransferOwnershipResponse proto.InternalMessageInfo + func init() { proto.RegisterType((*MsgFund)(nil), "haqq.dao.v1.MsgFund") proto.RegisterType((*MsgFundResponse)(nil), "haqq.dao.v1.MsgFundResponse") + proto.RegisterType((*MsgTransferOwnership)(nil), "haqq.dao.v1.MsgTransferOwnership") + proto.RegisterType((*MsgTransferOwnershipResponse)(nil), "haqq.dao.v1.MsgTransferOwnershipResponse") } func init() { proto.RegisterFile("haqq/dao/v1/tx.proto", fileDescriptor_32cf174189eaa32b) } var fileDescriptor_32cf174189eaa32b = []byte{ - // 391 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x12, 0xc9, 0x48, 0x2c, 0x2c, - 0xd4, 0x4f, 0x49, 0xcc, 0xd7, 0x2f, 0x33, 0xd4, 0x2f, 0xa9, 0xd0, 0x2b, 0x28, 0xca, 0x2f, 0xc9, - 0x17, 0xe2, 0x06, 0x89, 0xea, 0xa5, 0x24, 0xe6, 0xeb, 0x95, 0x19, 0x4a, 0x89, 0xa4, 0xe7, 0xa7, - 0xe7, 0x83, 0xc5, 0xf5, 0x41, 0x2c, 0x88, 0x12, 0x29, 0xb9, 0xe4, 0xfc, 0xe2, 0xdc, 0xfc, 0x62, - 0xfd, 0xa4, 0xc4, 0xe2, 0x54, 0xfd, 0x32, 0xc3, 0xa4, 0xd4, 0x92, 0x44, 0x43, 0xfd, 0xe4, 0xfc, - 0xcc, 0x3c, 0xa8, 0xbc, 0x24, 0x44, 0x3e, 0x1e, 0xa2, 0x11, 0xc2, 0x81, 0x4a, 0x89, 0x43, 0xb5, - 0xe6, 0x16, 0xa7, 0x83, 0x6c, 0xcd, 0x2d, 0x4e, 0x87, 0x4a, 0x08, 0x26, 0xe6, 0x66, 0xe6, 0xe5, - 0xeb, 0x83, 0x49, 0x88, 0x90, 0xd2, 0x0d, 0x46, 0x2e, 0x76, 0xdf, 0xe2, 0x74, 0xb7, 0xd2, 0xbc, - 0x14, 0xa1, 0x0c, 0x2e, 0xb6, 0xc4, 0xdc, 0xfc, 0xd2, 0xbc, 0x12, 0x09, 0x46, 0x05, 0x66, 0x0d, - 0x6e, 0x23, 0x49, 0x3d, 0xa8, 0xb1, 0x20, 0x37, 0xe8, 0x41, 0xdd, 0xa0, 0xe7, 0x9c, 0x9f, 0x99, - 0xe7, 0x64, 0x7a, 0xe2, 0x9e, 0x3c, 0xc3, 0xaa, 0xfb, 0xf2, 0x1a, 0xe9, 0x99, 0x25, 0x19, 0xa5, - 0x49, 0x7a, 0xc9, 0xf9, 0xb9, 0x50, 0x37, 0x40, 0x29, 0xdd, 0xe2, 0x94, 0x6c, 0xfd, 0x92, 0xca, - 0x82, 0xd4, 0x62, 0xb0, 0x86, 0xe2, 0x15, 0xcf, 0x37, 0x68, 0x31, 0x06, 0x41, 0xcd, 0x17, 0x32, - 0xe3, 0xe2, 0x4c, 0x49, 0x2d, 0xc8, 0x2f, 0xce, 0x2c, 0xc9, 0x2f, 0x92, 0x60, 0x52, 0x60, 0xd4, - 0xe0, 0x74, 0x92, 0xb8, 0xb4, 0x45, 0x57, 0x04, 0x6a, 0x9f, 0x63, 0x4a, 0x4a, 0x51, 0x6a, 0x71, - 0x71, 0x70, 0x49, 0x51, 0x66, 0x5e, 0x7a, 0x10, 0x42, 0xa9, 0x95, 0x76, 0xc7, 0x02, 0x79, 0x86, - 0x17, 0x0b, 0xe4, 0x19, 0x9a, 0x9e, 0x6f, 0xd0, 0x42, 0x88, 0x77, 0x3d, 0xdf, 0xa0, 0x25, 0x00, - 0x0f, 0x68, 0xa8, 0x77, 0x94, 0x04, 0xb9, 0xf8, 0xa1, 0xcc, 0xa0, 0xd4, 0xe2, 0x82, 0xfc, 0xbc, - 0xe2, 0x54, 0x23, 0x0f, 0x2e, 0x66, 0xdf, 0xe2, 0x74, 0x21, 0x2b, 0x2e, 0x16, 0xb0, 0x87, 0x45, - 0xf4, 0x90, 0xe2, 0x41, 0x0f, 0xaa, 0x58, 0x4a, 0x06, 0x9b, 0x28, 0xcc, 0x08, 0x29, 0xd6, 0x06, - 0x90, 0x4f, 0x9c, 0x9c, 0x4e, 0x3c, 0x92, 0x63, 0xbc, 0xf0, 0x48, 0x8e, 0xf1, 0xc1, 0x23, 0x39, - 0xc6, 0x09, 0x8f, 0xe5, 0x18, 0x2e, 0x3c, 0x96, 0x63, 0xb8, 0xf1, 0x58, 0x8e, 0x21, 0x0a, 0x39, - 0x48, 0x40, 0x06, 0xe9, 0xe6, 0xa5, 0x96, 0x94, 0xe7, 0x17, 0x65, 0x83, 0x39, 0xfa, 0x15, 0x60, - 0x27, 0x82, 0x03, 0x26, 0x89, 0x0d, 0x1c, 0x05, 0xc6, 0x80, 0x00, 0x00, 0x00, 0xff, 0xff, 0x91, - 0xd4, 0x66, 0x8c, 0x24, 0x02, 0x00, 0x00, + // 481 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x52, 0xb1, 0x6e, 0x13, 0x41, + 0x10, 0xbd, 0x25, 0x24, 0xe0, 0x4d, 0x01, 0x3e, 0x59, 0xc2, 0x39, 0x85, 0x73, 0x70, 0x65, 0x8c, + 0xbc, 0x2b, 0x07, 0x42, 0xe1, 0x0e, 0x23, 0xd1, 0x59, 0x48, 0x86, 0x8a, 0x26, 0x3a, 0xfb, 0x96, + 0xf5, 0x29, 0xba, 0x9d, 0xcb, 0xcd, 0xda, 0x0e, 0x1d, 0xa2, 0x42, 0x54, 0x7c, 0x42, 0x4a, 0x04, + 0x8d, 0x25, 0xf8, 0x88, 0x94, 0x11, 0x55, 0x2a, 0x40, 0x76, 0x61, 0x3e, 0x03, 0xdd, 0xde, 0x9a, + 0x58, 0x71, 0x24, 0x37, 0xf6, 0xce, 0x9b, 0x99, 0x37, 0x6f, 0xe6, 0x1e, 0x2d, 0x0d, 0x82, 0xe3, + 0x63, 0x1e, 0x06, 0xc0, 0x47, 0x4d, 0xae, 0x4f, 0x58, 0x92, 0x82, 0x06, 0x77, 0x3b, 0x43, 0x59, + 0x18, 0x00, 0x1b, 0x35, 0xbd, 0x92, 0x04, 0x09, 0x06, 0xe7, 0xd9, 0x2b, 0x2f, 0xf1, 0xfc, 0x3e, + 0x60, 0x0c, 0xc8, 0x7b, 0x01, 0x0a, 0x3e, 0x6a, 0xf6, 0x84, 0x0e, 0x9a, 0xbc, 0x0f, 0x91, 0xb2, + 0xf9, 0x9d, 0x3c, 0x7f, 0x98, 0x37, 0xe6, 0x81, 0x4d, 0xdd, 0xb3, 0xad, 0x31, 0xca, 0x6c, 0x6a, + 0x8c, 0xd2, 0x26, 0x8a, 0x41, 0x1c, 0x29, 0xe0, 0xe6, 0x37, 0x87, 0xaa, 0x17, 0x84, 0xde, 0xea, + 0xa0, 0x7c, 0x31, 0x54, 0xa1, 0x3b, 0xa0, 0x5b, 0x41, 0x0c, 0x43, 0xa5, 0xcb, 0x64, 0x6f, 0xa3, + 0xb6, 0xbd, 0xbf, 0xc3, 0x2c, 0x6d, 0xa6, 0x81, 0x59, 0x0d, 0xec, 0x39, 0x44, 0xaa, 0x7d, 0x70, + 0xf6, 0xab, 0xe2, 0x7c, 0xfd, 0x5d, 0xa9, 0xc9, 0x48, 0x0f, 0x86, 0x3d, 0xd6, 0x87, 0xd8, 0x6a, + 0xb0, 0x7f, 0x0d, 0x0c, 0x8f, 0xb8, 0x7e, 0x97, 0x08, 0x34, 0x0d, 0xf8, 0x65, 0x3e, 0xa9, 0x93, + 0xae, 0xe5, 0x77, 0x9f, 0xd2, 0x42, 0x28, 0x12, 0xc0, 0x48, 0x43, 0x5a, 0xbe, 0xb1, 0x47, 0x6a, + 0x85, 0x76, 0xf9, 0xe7, 0x8f, 0x46, 0xc9, 0xce, 0x7b, 0x16, 0x86, 0xa9, 0x40, 0x7c, 0xa5, 0xd3, + 0x48, 0xc9, 0xee, 0x65, 0x69, 0xeb, 0xd1, 0xc7, 0xd3, 0x8a, 0xf3, 0xf7, 0xb4, 0xe2, 0x7c, 0x98, + 0x4f, 0xea, 0x97, 0xf8, 0xa7, 0xf9, 0xa4, 0x7e, 0xf7, 0xff, 0xa1, 0xed, 0x3a, 0xd5, 0x22, 0xbd, + 0x63, 0x9f, 0x5d, 0x81, 0x09, 0x28, 0x14, 0xd5, 0xef, 0x84, 0x96, 0x3a, 0x28, 0x5f, 0xa7, 0x81, + 0xc2, 0xb7, 0x22, 0x7d, 0x39, 0x56, 0x22, 0xc5, 0x41, 0x94, 0xb8, 0x8c, 0x6e, 0x42, 0x16, 0x94, + 0xc9, 0x1a, 0x31, 0x79, 0x99, 0x7b, 0x40, 0x0b, 0x4a, 0x8c, 0x0f, 0xf3, 0x9e, 0x75, 0x0b, 0xdc, + 0x56, 0x62, 0x6c, 0x46, 0xb5, 0x9e, 0x2c, 0xeb, 0xcf, 0xa9, 0x32, 0xed, 0xf7, 0x97, 0xb5, 0xaf, + 0x88, 0xab, 0xfa, 0x74, 0xf7, 0x3a, 0x7c, 0xb1, 0xd5, 0xfe, 0x37, 0x42, 0x37, 0x3a, 0x28, 0xdd, + 0x16, 0xbd, 0x69, 0xbe, 0x63, 0x89, 0x2d, 0xd9, 0x8b, 0xd9, 0x1b, 0x78, 0xbb, 0xd7, 0xa1, 0x0b, + 0x0e, 0x37, 0xa0, 0xc5, 0xd5, 0xab, 0x3c, 0xb8, 0xda, 0xb2, 0x52, 0xe2, 0x3d, 0x5c, 0x5b, 0xb2, + 0x18, 0xe1, 0x6d, 0xbe, 0xcf, 0x3c, 0xd0, 0x6e, 0x9f, 0x4d, 0x7d, 0x72, 0x3e, 0xf5, 0xc9, 0x9f, + 0xa9, 0x4f, 0x3e, 0xcf, 0x7c, 0xe7, 0x7c, 0xe6, 0x3b, 0x17, 0x33, 0xdf, 0x79, 0xb3, 0x6c, 0xa6, + 0x8c, 0xb5, 0xa1, 0x84, 0x1e, 0x43, 0x7a, 0x64, 0x02, 0x7e, 0x62, 0x0e, 0x64, 0x2c, 0xd5, 0xdb, + 0x32, 0xe6, 0x7d, 0xfc, 0x2f, 0x00, 0x00, 0xff, 0xff, 0x44, 0xa1, 0xe5, 0x5b, 0x5e, 0x03, 0x00, + 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -159,6 +245,8 @@ const _ = grpc.SupportPackageIsVersion4 type MsgClient interface { // Fund defines a method to allow an account to directly fund the dao. Fund(ctx context.Context, in *MsgFund, opts ...grpc.CallOption) (*MsgFundResponse, error) + // TransferOwnership defines a method to allow an account to transfer the ownership of shares to another account. + TransferOwnership(ctx context.Context, in *MsgTransferOwnership, opts ...grpc.CallOption) (*MsgTransferOwnershipResponse, error) } type msgClient struct { @@ -178,10 +266,21 @@ func (c *msgClient) Fund(ctx context.Context, in *MsgFund, opts ...grpc.CallOpti return out, nil } +func (c *msgClient) TransferOwnership(ctx context.Context, in *MsgTransferOwnership, opts ...grpc.CallOption) (*MsgTransferOwnershipResponse, error) { + out := new(MsgTransferOwnershipResponse) + err := c.cc.Invoke(ctx, "/haqq.dao.v1.Msg/TransferOwnership", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // MsgServer is the server API for Msg service. type MsgServer interface { // Fund defines a method to allow an account to directly fund the dao. Fund(context.Context, *MsgFund) (*MsgFundResponse, error) + // TransferOwnership defines a method to allow an account to transfer the ownership of shares to another account. + TransferOwnership(context.Context, *MsgTransferOwnership) (*MsgTransferOwnershipResponse, error) } // UnimplementedMsgServer can be embedded to have forward compatible implementations. @@ -191,6 +290,9 @@ type UnimplementedMsgServer struct { func (*UnimplementedMsgServer) Fund(ctx context.Context, req *MsgFund) (*MsgFundResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method Fund not implemented") } +func (*UnimplementedMsgServer) TransferOwnership(ctx context.Context, req *MsgTransferOwnership) (*MsgTransferOwnershipResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method TransferOwnership not implemented") +} func RegisterMsgServer(s grpc1.Server, srv MsgServer) { s.RegisterService(&_Msg_serviceDesc, srv) @@ -214,6 +316,24 @@ func _Msg_Fund_Handler(srv interface{}, ctx context.Context, dec func(interface{ return interceptor(ctx, in, info, handler) } +func _Msg_TransferOwnership_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgTransferOwnership) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).TransferOwnership(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/haqq.dao.v1.Msg/TransferOwnership", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).TransferOwnership(ctx, req.(*MsgTransferOwnership)) + } + return interceptor(ctx, in, info, handler) +} + var _Msg_serviceDesc = grpc.ServiceDesc{ ServiceName: "haqq.dao.v1.Msg", HandlerType: (*MsgServer)(nil), @@ -222,6 +342,10 @@ var _Msg_serviceDesc = grpc.ServiceDesc{ MethodName: "Fund", Handler: _Msg_Fund_Handler, }, + { + MethodName: "TransferOwnership", + Handler: _Msg_TransferOwnership_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "haqq/dao/v1/tx.proto", @@ -294,6 +418,66 @@ func (m *MsgFundResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *MsgTransferOwnership) 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 *MsgTransferOwnership) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgTransferOwnership) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.NewOwner) > 0 { + i -= len(m.NewOwner) + copy(dAtA[i:], m.NewOwner) + i = encodeVarintTx(dAtA, i, uint64(len(m.NewOwner))) + i-- + dAtA[i] = 0x12 + } + if len(m.Owner) > 0 { + i -= len(m.Owner) + copy(dAtA[i:], m.Owner) + i = encodeVarintTx(dAtA, i, uint64(len(m.Owner))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgTransferOwnershipResponse) 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 *MsgTransferOwnershipResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgTransferOwnershipResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + func encodeVarintTx(dAtA []byte, offset int, v uint64) int { offset -= sovTx(v) base := offset @@ -333,6 +517,32 @@ func (m *MsgFundResponse) Size() (n int) { return n } +func (m *MsgTransferOwnership) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Owner) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.NewOwner) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func (m *MsgTransferOwnershipResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + func sovTx(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 } @@ -505,6 +715,170 @@ func (m *MsgFundResponse) Unmarshal(dAtA []byte) error { } return nil } +func (m *MsgTransferOwnership) 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 ErrIntOverflowTx + } + 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: MsgTransferOwnership: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgTransferOwnership: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Owner", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + 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 ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Owner = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field NewOwner", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + 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 ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.NewOwner = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgTransferOwnershipResponse) 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 ErrIntOverflowTx + } + 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: MsgTransferOwnershipResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgTransferOwnershipResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func skipTx(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0