diff --git a/integration_tests/axelarcork_test.go b/integration_tests/axelarcork_test.go index 4cc681fa..8cb5f00e 100644 --- a/integration_tests/axelarcork_test.go +++ b/integration_tests/axelarcork_test.go @@ -10,6 +10,9 @@ import ( "cosmossdk.io/math" "github.com/cosmos/cosmos-sdk/client" sdk "github.com/cosmos/cosmos-sdk/types" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + distributiontypes "github.com/cosmos/cosmos-sdk/x/distribution/types" govtypesv1beta1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1" "github.com/ethereum/go-ethereum/common" "github.com/golang/protobuf/proto" //nolint:staticcheck @@ -456,6 +459,53 @@ func (s *IntegrationTestSuite) TestAxelarCork() { chainConfigurationsResponse, err = axelarcorkQueryClient.QueryChainConfigurations(context.Background(), &types.QueryChainConfigurationsRequest{}) s.Require().NoError(err) s.Require().Empty(chainConfigurationsResponse.Configurations) + + ////////////////////////////////////////// + // Test module account balance sweeping // + ////////////////////////////////////////// + + // Get the baseline balance of the distribution community pool, send funds to the axelarcork module account, + // verify they are received, and that the balance is zero on the next block. + s.T().Log("Querying distribution community pool balance") + distributionQueryClient := distributiontypes.NewQueryClient(orch0ClientCtx) + distributionCommunityPoolResponse, err := distributionQueryClient.CommunityPool(context.Background(), &distributiontypes.QueryCommunityPoolRequest{}) + s.Require().NoError(err) + initialPool := distributionCommunityPoolResponse.Pool + + // Send all of orchestrator's sweep denom and some usomm + s.T().Log("Querying orchestrator account balances") + bankQueryClient := banktypes.NewQueryClient(orch0ClientCtx) + orch0AccountResponse, err := bankQueryClient.AllBalances(context.Background(), &banktypes.QueryAllBalancesRequest{Address: orch0.address().String()}) + s.Require().NoError(err) + orch0Balances := orch0AccountResponse.Balances + usommToSend := sdk.NewCoin(testDenom, math.NewInt(1000)) + found, sweepDenomToSend := orch0Balances.Find(axelarSweepDenom) + s.Require().True(found, "orch0 doesn't have any sweep test denom funds") + orch0SweepFunds := sdk.Coins{ + sweepDenomToSend, + usommToSend, + } + + s.T().Log("Sending funds to axelarcork module account") + axelarcorkModuleAddress := authtypes.NewModuleAddress(types.ModuleName) + sendFundsToAxelarcorkMsg := banktypes.NewMsgSend( + orch0.address(), + axelarcorkModuleAddress, + orch0SweepFunds, + ) + sendResponse, err := s.chain.sendMsgs(*orch0ClientCtx, sendFundsToAxelarcorkMsg) + s.Require().NoError(err) + s.Require().Zero(sendResponse.Code, "raw log: %s", sendResponse.RawLog) + s.T().Log("Verifying distribution community pool balances includes the swept funds") + + // Short delay to ensure a new block is queried + time.Sleep(10 * time.Second) + + // Verify fund appear in the community pool + distributionCommunityPoolResponse, err = distributionQueryClient.CommunityPool(context.Background(), &distributiontypes.QueryCommunityPoolRequest{}) + s.Require().NoError(err) + poolAfterSweep := initialPool.Add(sdk.NewDecCoinsFromCoins(usommToSend)...).Add(sdk.NewDecCoinsFromCoins(sweepDenomToSend)...) + s.Require().Equal(poolAfterSweep, distributionCommunityPoolResponse.Pool) }) } diff --git a/integration_tests/setup_test.go b/integration_tests/setup_test.go index e0b6e852..47dac1a0 100644 --- a/integration_tests/setup_test.go +++ b/integration_tests/setup_test.go @@ -68,6 +68,7 @@ HOqHGS8ApZcunRauDAIwRtgceZpkS92KuP3QOUotAH/nnCzp7X1lVzGOSTBRTVYJ pohf4PJrfacqpi7PoXBk -----END CERTIFICATE----- ` + axelarSweepDenom = "sweep" ) var ( @@ -319,7 +320,19 @@ func (s *IntegrationTestSuite) initGenesis() { Exponent: 0, }, }, - }) + }, + banktypes.Metadata{ + Description: "Test token for sweeping", + Display: axelarSweepDenom, + Base: axelarSweepDenom, + Name: axelarSweepDenom, + DenomUnits: []*banktypes.DenomUnit{ + { + Denom: axelarSweepDenom, + Exponent: 0, + }, + }, + }) // Set up auction module with some coins to auction off balance := banktypes.Balance{ @@ -330,8 +343,13 @@ func (s *IntegrationTestSuite) initGenesis() { Address: authtypes.NewModuleAddress(disttypes.ModuleName).String(), Coins: sdk.NewCoins(sdk.NewCoin(params.BaseCoinUnit, sdk.NewInt(1000000000))), } + orchSweepBalance := banktypes.Balance{ + Address: s.chain.orchestrators[0].address().String(), + Coins: sdk.NewCoins(sdk.NewCoin(axelarSweepDenom, sdk.NewInt(2000000000))), + } bankGenState.Balances = append(bankGenState.Balances, balance) bankGenState.Balances = append(bankGenState.Balances, distBalance) + bankGenState.Balances = append(bankGenState.Balances, orchSweepBalance) bz, err := cdc.MarshalJSON(&bankGenState) s.Require().NoError(err) diff --git a/x/axelarcork/keeper/abci.go b/x/axelarcork/keeper/abci.go index 97f92d1b..f9fa4a3b 100644 --- a/x/axelarcork/keeper/abci.go +++ b/x/axelarcork/keeper/abci.go @@ -5,6 +5,7 @@ import ( "github.com/ethereum/go-ethereum/common" + distributionTypes "github.com/cosmos/cosmos-sdk/x/distribution/types" "github.com/peggyjv/sommelier/v7/x/axelarcork/types" sdk "github.com/cosmos/cosmos-sdk/types" @@ -54,4 +55,30 @@ func (k Keeper) EndBlocker(ctx sdk.Context) { return false }) + + // Sweep all axelarcork sender module account balances to the community pool. Because this account is the + // sender for transfers created by RelayCork calls, funds will not be returned to the caller if the IBC + // transfer fails or gas is refunded. + moduleAcct := k.GetSenderAccount(ctx) + balances := k.bankKeeper.GetAllBalances(ctx, moduleAcct.GetAddress()) + balancesForPool := sdk.Coins{} + + for _, b := range balances { + if b.Amount.IsPositive() { + balancesForPool.Add(b) + } + } + + if balancesForPool.Len() == 0 { + return + } + + if err := k.bankKeeper.SendCoinsFromModuleToModule(ctx, types.ModuleName, distributionTypes.ModuleName, balancesForPool); err != nil { + panic(err) + } + + feePool := k.distributionKeeper.GetFeePool(ctx) + feePool.CommunityPool = feePool.CommunityPool.Add(sdk.NewDecCoinsFromCoins(balancesForPool...)...) + + k.distributionKeeper.SetFeePool(ctx, feePool) }