diff --git a/testutil/integration/helpers.go b/testutil/integration/helpers.go index 514aea52..a1ffc938 100644 --- a/testutil/integration/helpers.go +++ b/testutil/integration/helpers.go @@ -5,6 +5,16 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" ) +func (suite *KeeperTestSuite) GetCoinsFromCommunityPool() sdk.Coins { + pool, err := suite.App().DistributionKeeper.FeePool.Get(suite.Ctx()) + if err != nil { + return sdk.NewCoins() + } + + coins, _ := pool.CommunityPool.TruncateDecimal() + return coins +} + func (suite *KeeperTestSuite) GetBalanceFromAddress(address string) uint64 { accAddress, err := sdk.AccAddressFromBech32(address) if err != nil { diff --git a/x/bundles/keeper/keeper_suite_funding_bundles_test.go b/x/bundles/keeper/keeper_suite_funding_bundles_test.go index e8ff2a30..446c1032 100644 --- a/x/bundles/keeper/keeper_suite_funding_bundles_test.go +++ b/x/bundles/keeper/keeper_suite_funding_bundles_test.go @@ -5,8 +5,10 @@ import ( i "github.com/KYVENetwork/chain/testutil/integration" bundletypes "github.com/KYVENetwork/chain/x/bundles/types" funderstypes "github.com/KYVENetwork/chain/x/funders/types" + globaltypes "github.com/KYVENetwork/chain/x/global/types" pooltypes "github.com/KYVENetwork/chain/x/pool/types" stakertypes "github.com/KYVENetwork/chain/x/stakers/types" + sdk "github.com/cosmos/cosmos-sdk/types" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) @@ -23,19 +25,22 @@ TEST CASES - funding bundles * Produce a valid bundle although multiple funders with same amount can not pay for the bundle reward * Produce a valid bundle although multiple funders with different amount can not pay for the bundle reward * Produce a valid bundle although there are no funders at all +* Produce a valid bundle with only one funder and multiple coins +* Produce a valid bundle with multiple funders and multiple coins +* Produce a valid bundle although the only funder can not pay for the full bundle reward */ var _ = Describe("funding bundles", Ordered, func() { var s *i.KeeperTestSuite - var initialBalanceAlice uint64 - var initialBalanceBob uint64 + var initialBalanceAlice sdk.Coins + var initialBalanceBob sdk.Coins BeforeEach(func() { // init new clean chain s = i.NewCleanChain() - initialBalanceAlice = s.GetBalanceFromAddress(i.ALICE) - initialBalanceBob = s.GetBalanceFromAddress(i.BOB) + initialBalanceAlice = s.GetCoinsFromAddress(i.ALICE) + initialBalanceBob = s.GetCoinsFromAddress(i.BOB) params := s.App().FundersKeeper.GetParams(s.Ctx()) params.MinFundingMultiple = 0 @@ -61,6 +66,34 @@ var _ = Describe("funding bundles", Ordered, func() { } s.RunTxPoolSuccess(msg) + // set whitelist + s.App().FundersKeeper.SetParams(s.Ctx(), funderstypes.NewParams([]*funderstypes.WhitelistCoinEntry{ + { + CoinDenom: globaltypes.Denom, + MinFundingAmount: 10 * i.KYVE, + MinFundingAmountPerBundle: 1 * i.KYVE, + CoinWeight: math.LegacyNewDec(1), + }, + { + CoinDenom: i.A_DENOM, + MinFundingAmount: 10 * i.KYVE, + MinFundingAmountPerBundle: 1 * i.KYVE, + CoinWeight: math.LegacyNewDec(1), + }, + { + CoinDenom: i.B_DENOM, + MinFundingAmount: 10 * i.KYVE, + MinFundingAmountPerBundle: 1 * i.KYVE, + CoinWeight: math.LegacyNewDec(2), + }, + { + CoinDenom: i.C_DENOM, + MinFundingAmount: 10 * i.KYVE, + MinFundingAmountPerBundle: 1 * i.KYVE, + CoinWeight: math.LegacyNewDec(3), + }, + }, 0)) + // create funders s.RunTxFundersSuccess(&funderstypes.MsgCreateFunder{ Creator: i.ALICE, @@ -109,8 +142,8 @@ var _ = Describe("funding bundles", Ordered, func() { s.RunTxFundersSuccess(&funderstypes.MsgFundPool{ Creator: i.ALICE, PoolId: 0, - Amounts: i.KYVECoins(100 * i.T_KYVE), - AmountsPerBundle: i.KYVECoins(10 * i.T_KYVE), + Amounts: i.ACoins(100 * i.T_KYVE), + AmountsPerBundle: i.ACoins(10 * i.T_KYVE), }) s.CommitAfterSeconds(60) @@ -164,18 +197,18 @@ var _ = Describe("funding bundles", Ordered, func() { fundingState, _ := s.App().FundersKeeper.GetFundingState(s.Ctx(), 0) // assert total pool funds - Expect(s.App().FundersKeeper.GetTotalActiveFunding(s.Ctx(), fundingState.PoolId)[0].Amount.Uint64()).To(Equal(90 * i.KYVE)) + Expect(s.App().FundersKeeper.GetTotalActiveFunding(s.Ctx(), fundingState.PoolId).String()).To(Equal(i.ACoins(90 * i.T_KYVE).String())) Expect(fundingState.ActiveFunderAddresses).To(HaveLen(1)) funding, _ := s.App().FundersKeeper.GetFunding(s.Ctx(), i.ALICE, 0) // assert individual funds - Expect(funding.Amounts[0].Amount.Uint64()).To(Equal(90 * i.KYVE)) - Expect(funding.TotalFunded[0].Amount.Uint64()).To(Equal(10 * i.KYVE)) + Expect(funding.Amounts.String()).To(Equal(i.ACoins(90 * i.T_KYVE).String())) + Expect(funding.TotalFunded.String()).To(Equal(i.ACoins(10 * i.T_KYVE).String())) // assert individual balances - balanceAlice := s.GetBalanceFromAddress(i.ALICE) - Expect(balanceAlice).To(Equal(initialBalanceAlice - 100*i.KYVE)) + balanceAlice := s.GetCoinsFromAddress(i.ALICE) + Expect(balanceAlice.String()).To(Equal(initialBalanceAlice.Sub(i.ACoin(100 * i.T_KYVE)).String())) }) It("Produce a valid bundle with multiple funders and same funding amounts", func() { @@ -183,15 +216,15 @@ var _ = Describe("funding bundles", Ordered, func() { s.RunTxFundersSuccess(&funderstypes.MsgFundPool{ Creator: i.ALICE, PoolId: 0, - Amounts: i.KYVECoins(100 * i.T_KYVE), - AmountsPerBundle: i.KYVECoins(10 * i.T_KYVE), + Amounts: i.ACoins(100 * i.T_KYVE), + AmountsPerBundle: i.ACoins(10 * i.T_KYVE), }) s.RunTxFundersSuccess(&funderstypes.MsgFundPool{ Creator: i.BOB, PoolId: 0, - Amounts: i.KYVECoins(100 * i.T_KYVE), - AmountsPerBundle: i.KYVECoins(10 * i.T_KYVE), + Amounts: i.ACoins(100 * i.T_KYVE), + AmountsPerBundle: i.ACoins(10 * i.T_KYVE), }) s.CommitAfterSeconds(60) @@ -245,24 +278,24 @@ var _ = Describe("funding bundles", Ordered, func() { fundingState, _ := s.App().FundersKeeper.GetFundingState(s.Ctx(), 0) // assert total pool funds - Expect(s.App().FundersKeeper.GetTotalActiveFunding(s.Ctx(), fundingState.PoolId)[0].Amount.Uint64()).To(Equal(180 * i.KYVE)) + Expect(s.App().FundersKeeper.GetTotalActiveFunding(s.Ctx(), fundingState.PoolId).String()).To(Equal(i.ACoins(180 * i.T_KYVE).String())) Expect(fundingState.ActiveFunderAddresses).To(HaveLen(2)) fundingAlice, _ := s.App().FundersKeeper.GetFunding(s.Ctx(), i.ALICE, 0) fundingBob, _ := s.App().FundersKeeper.GetFunding(s.Ctx(), i.BOB, 0) // assert individual funds - Expect(fundingAlice.Amounts[0].Amount.Uint64()).To(Equal(90 * i.KYVE)) - Expect(fundingAlice.TotalFunded[0].Amount.Uint64()).To(Equal(10 * i.KYVE)) - Expect(fundingBob.Amounts[0].Amount.Uint64()).To(Equal(90 * i.KYVE)) - Expect(fundingBob.TotalFunded[0].Amount.Uint64()).To(Equal(10 * i.KYVE)) + Expect(fundingAlice.Amounts.String()).To(Equal(i.ACoins(90 * i.T_KYVE).String())) + Expect(fundingAlice.TotalFunded.String()).To(Equal(i.ACoins(10 * i.T_KYVE).String())) + Expect(fundingBob.Amounts.String()).To(Equal(i.ACoins(90 * i.T_KYVE).String())) + Expect(fundingBob.TotalFunded.String()).To(Equal(i.ACoins(10 * i.T_KYVE).String())) // assert individual balances - balanceAlice := s.GetBalanceFromAddress(i.ALICE) - Expect(balanceAlice).To(Equal(initialBalanceAlice - 100*i.KYVE)) + balanceAlice := s.GetCoinsFromAddress(i.ALICE) + Expect(balanceAlice.String()).To(Equal(initialBalanceAlice.Sub(i.ACoin(100 * i.T_KYVE)).String())) - balanceBob := s.GetBalanceFromAddress(i.BOB) - Expect(balanceBob).To(Equal(initialBalanceBob - 100*i.KYVE)) + balanceBob := s.GetCoinsFromAddress(i.BOB) + Expect(balanceBob.String()).To(Equal(initialBalanceBob.Sub(i.ACoin(100 * i.T_KYVE)).String())) }) It("Produce a valid bundle with multiple funders and different funding amounts", func() { @@ -270,15 +303,15 @@ var _ = Describe("funding bundles", Ordered, func() { s.RunTxFundersSuccess(&funderstypes.MsgFundPool{ Creator: i.ALICE, PoolId: 0, - Amounts: i.KYVECoins(150 * i.T_KYVE), - AmountsPerBundle: i.KYVECoins(15 * i.T_KYVE), + Amounts: i.ACoins(150 * i.T_KYVE), + AmountsPerBundle: i.ACoins(15 * i.T_KYVE), }) s.RunTxFundersSuccess(&funderstypes.MsgFundPool{ Creator: i.BOB, PoolId: 0, - Amounts: i.KYVECoins(50 * i.T_KYVE), - AmountsPerBundle: i.KYVECoins(5 * i.T_KYVE), + Amounts: i.ACoins(50 * i.T_KYVE), + AmountsPerBundle: i.ACoins(5 * i.T_KYVE), }) s.CommitAfterSeconds(60) @@ -332,24 +365,24 @@ var _ = Describe("funding bundles", Ordered, func() { fundingState, _ := s.App().FundersKeeper.GetFundingState(s.Ctx(), 0) // assert total pool funds - Expect(s.App().FundersKeeper.GetTotalActiveFunding(s.Ctx(), fundingState.PoolId)[0].Amount.Uint64()).To(Equal(180 * i.KYVE)) + Expect(s.App().FundersKeeper.GetTotalActiveFunding(s.Ctx(), fundingState.PoolId).String()).To(Equal(i.ACoins(180 * i.T_KYVE).String())) Expect(fundingState.ActiveFunderAddresses).To(HaveLen(2)) fundingAlice, _ := s.App().FundersKeeper.GetFunding(s.Ctx(), i.ALICE, 0) fundingBob, _ := s.App().FundersKeeper.GetFunding(s.Ctx(), i.BOB, 0) // assert individual funds - Expect(fundingAlice.Amounts[0].Amount.Uint64()).To(Equal(135 * i.KYVE)) - Expect(fundingAlice.TotalFunded[0].Amount.Uint64()).To(Equal(15 * i.KYVE)) - Expect(fundingBob.Amounts[0].Amount.Uint64()).To(Equal(45 * i.KYVE)) - Expect(fundingBob.TotalFunded[0].Amount.Uint64()).To(Equal(5 * i.KYVE)) + Expect(fundingAlice.Amounts.String()).To(Equal(i.ACoins(135 * i.T_KYVE).String())) + Expect(fundingAlice.TotalFunded.String()).To(Equal(i.ACoins(15 * i.T_KYVE).String())) + Expect(fundingBob.Amounts.String()).To(Equal(i.ACoins(45 * i.T_KYVE).String())) + Expect(fundingBob.TotalFunded.String()).To(Equal(i.ACoins(5 * i.T_KYVE).String())) // assert individual balances - balanceAlice := s.GetBalanceFromAddress(i.ALICE) - Expect(balanceAlice).To(Equal(initialBalanceAlice - 150*i.KYVE)) + balanceAlice := s.GetCoinsFromAddress(i.ALICE) + Expect(balanceAlice.String()).To(Equal(initialBalanceAlice.Sub(i.ACoin(150 * i.T_KYVE)).String())) - balanceBob := s.GetBalanceFromAddress(i.BOB) - Expect(balanceBob).To(Equal(initialBalanceBob - 50*i.KYVE)) + balanceBob := s.GetCoinsFromAddress(i.BOB) + Expect(balanceBob.String()).To(Equal(initialBalanceBob.Sub(i.ACoin(50 * i.T_KYVE)).String())) }) It("Produce a valid bundle with multiple funders and different funding amounts where not everyone can afford the full funds", func() { @@ -357,15 +390,15 @@ var _ = Describe("funding bundles", Ordered, func() { s.RunTxFundersSuccess(&funderstypes.MsgFundPool{ Creator: i.ALICE, PoolId: 0, - Amounts: i.KYVECoins(10 * i.T_KYVE), - AmountsPerBundle: i.KYVECoins(50 * i.T_KYVE), + Amounts: i.ACoins(10 * i.T_KYVE), + AmountsPerBundle: i.ACoins(50 * i.T_KYVE), }) s.RunTxFundersSuccess(&funderstypes.MsgFundPool{ Creator: i.BOB, PoolId: 0, - Amounts: i.KYVECoins(100 * i.T_KYVE), - AmountsPerBundle: i.KYVECoins(50 * i.T_KYVE), + Amounts: i.ACoins(100 * i.T_KYVE), + AmountsPerBundle: i.ACoins(50 * i.T_KYVE), }) s.CommitAfterSeconds(60) @@ -419,7 +452,7 @@ var _ = Describe("funding bundles", Ordered, func() { fundingState, _ := s.App().FundersKeeper.GetFundingState(s.Ctx(), 0) // assert total pool funds - Expect(s.App().FundersKeeper.GetTotalActiveFunding(s.Ctx(), fundingState.PoolId)[0].Amount.Uint64()).To(Equal(50 * i.KYVE)) + Expect(s.App().FundersKeeper.GetTotalActiveFunding(s.Ctx(), fundingState.PoolId).String()).To(Equal(i.ACoins(50 * i.T_KYVE).String())) Expect(fundingState.ActiveFunderAddresses).To(HaveLen(1)) Expect(fundingState.ActiveFunderAddresses[0]).To(Equal(i.BOB)) @@ -428,16 +461,16 @@ var _ = Describe("funding bundles", Ordered, func() { // assert individual funds Expect(fundingAlice.Amounts.IsZero()).To(BeTrue()) - Expect(fundingAlice.TotalFunded[0].Amount.Uint64()).To(Equal(10 * i.KYVE)) - Expect(fundingBob.Amounts[0].Amount.Uint64()).To(Equal(50 * i.KYVE)) - Expect(fundingBob.TotalFunded[0].Amount.Uint64()).To(Equal(50 * i.KYVE)) + Expect(fundingAlice.TotalFunded.String()).To(Equal(i.ACoins(10 * i.T_KYVE).String())) + Expect(fundingBob.Amounts.String()).To(Equal(i.ACoins(50 * i.T_KYVE).String())) + Expect(fundingBob.TotalFunded.String()).To(Equal(i.ACoins(50 * i.T_KYVE).String())) // assert individual balances - balanceAlice := s.GetBalanceFromAddress(i.ALICE) - Expect(balanceAlice).To(Equal(initialBalanceAlice - 10*i.KYVE)) + balanceAlice := s.GetCoinsFromAddress(i.ALICE) + Expect(balanceAlice.String()).To(Equal(initialBalanceAlice.Sub(i.ACoin(10 * i.T_KYVE)).String())) - balanceBob := s.GetBalanceFromAddress(i.BOB) - Expect(balanceBob).To(Equal(initialBalanceBob - 100*i.KYVE)) + balanceBob := s.GetCoinsFromAddress(i.BOB) + Expect(balanceBob.String()).To(Equal(initialBalanceBob.Sub(i.ACoin(100 * i.T_KYVE)).String())) }) It("Produce a valid bundle although the only funder can not pay for the full bundle reward", func() { @@ -445,8 +478,8 @@ var _ = Describe("funding bundles", Ordered, func() { s.RunTxFundersSuccess(&funderstypes.MsgFundPool{ Creator: i.ALICE, PoolId: 0, - Amounts: i.KYVECoins(10 * i.T_KYVE), - AmountsPerBundle: i.KYVECoins(20 * i.T_KYVE), + Amounts: i.ACoins(10 * i.T_KYVE), + AmountsPerBundle: i.ACoins(20 * i.T_KYVE), }) s.CommitAfterSeconds(60) @@ -507,11 +540,11 @@ var _ = Describe("funding bundles", Ordered, func() { // assert individual funds Expect(fundingAlice.Amounts.IsZero()).To(BeTrue()) - Expect(fundingAlice.TotalFunded[0].Amount.Uint64()).To(Equal(10 * i.KYVE)) + Expect(fundingAlice.TotalFunded.String()).To(Equal(i.ACoins(10 * i.T_KYVE).String())) // assert individual balances - balanceAlice := s.GetBalanceFromAddress(i.ALICE) - Expect(balanceAlice).To(Equal(initialBalanceAlice - 10*i.KYVE)) + balanceAlice := s.GetCoinsFromAddress(i.ALICE) + Expect(balanceAlice.String()).To(Equal(initialBalanceAlice.Sub(i.ACoin(10 * i.T_KYVE)).String())) }) It("Produce a valid bundle although multiple funders with same amount can not pay for the bundle reward", func() { @@ -519,15 +552,15 @@ var _ = Describe("funding bundles", Ordered, func() { s.RunTxFundersSuccess(&funderstypes.MsgFundPool{ Creator: i.ALICE, PoolId: 0, - Amounts: i.KYVECoins(10 * i.T_KYVE), - AmountsPerBundle: i.KYVECoins(20 * i.T_KYVE), + Amounts: i.ACoins(10 * i.T_KYVE), + AmountsPerBundle: i.ACoins(20 * i.T_KYVE), }) s.RunTxFundersSuccess(&funderstypes.MsgFundPool{ Creator: i.BOB, PoolId: 0, - Amounts: i.KYVECoins(10 * i.T_KYVE), - AmountsPerBundle: i.KYVECoins(20 * i.T_KYVE), + Amounts: i.ACoins(10 * i.T_KYVE), + AmountsPerBundle: i.ACoins(20 * i.T_KYVE), }) s.CommitAfterSeconds(60) @@ -586,11 +619,11 @@ var _ = Describe("funding bundles", Ordered, func() { Expect(fundingState.ActiveFunderAddresses).To(HaveLen(0)) // assert individual balances - balanceAlice := s.GetBalanceFromAddress(i.ALICE) - Expect(balanceAlice).To(Equal(initialBalanceAlice - 10*i.KYVE)) + balanceAlice := s.GetCoinsFromAddress(i.ALICE) + Expect(balanceAlice.String()).To(Equal(initialBalanceAlice.Sub(i.ACoin(10 * i.T_KYVE)).String())) - balanceBob := s.GetBalanceFromAddress(i.BOB) - Expect(balanceBob).To(Equal(initialBalanceBob - 10*i.KYVE)) + balanceBob := s.GetCoinsFromAddress(i.BOB) + Expect(balanceBob.String()).To(Equal(initialBalanceBob.Sub(i.ACoin(10 * i.T_KYVE)).String())) }) It("Produce a dropped bundle because multiple funders with different amount can not pay for the bundle reward", func() { @@ -598,15 +631,15 @@ var _ = Describe("funding bundles", Ordered, func() { s.RunTxFundersSuccess(&funderstypes.MsgFundPool{ Creator: i.ALICE, PoolId: 0, - Amounts: i.KYVECoins(10 * i.T_KYVE), - AmountsPerBundle: i.KYVECoins(10 * i.T_KYVE), + Amounts: i.ACoins(10 * i.T_KYVE), + AmountsPerBundle: i.ACoins(10 * i.T_KYVE), }) s.RunTxFundersSuccess(&funderstypes.MsgFundPool{ Creator: i.BOB, PoolId: 0, - Amounts: i.KYVECoins(20 * i.T_KYVE), - AmountsPerBundle: i.KYVECoins(20 * i.T_KYVE), + Amounts: i.ACoins(20 * i.T_KYVE), + AmountsPerBundle: i.ACoins(20 * i.T_KYVE), }) s.CommitAfterSeconds(60) @@ -667,11 +700,11 @@ var _ = Describe("funding bundles", Ordered, func() { // assert individual funds Expect(fundingAlice.Amounts.IsZero()).To(BeTrue()) - Expect(fundingAlice.TotalFunded[0].Amount.Uint64()).To(Equal(10 * i.KYVE)) + Expect(fundingAlice.TotalFunded.String()).To(Equal(i.ACoins(10 * i.T_KYVE).String())) // assert individual balances - balanceAlice := s.GetBalanceFromAddress(i.ALICE) - Expect(balanceAlice).To(Equal(initialBalanceAlice - 10*i.KYVE)) + balanceAlice := s.GetCoinsFromAddress(i.ALICE) + Expect(balanceAlice.String()).To(Equal(initialBalanceAlice.Sub(i.ACoin(10 * i.T_KYVE)).String())) }) It("Produce a valid bundle although there are no funders at all", func() { @@ -736,4 +769,239 @@ var _ = Describe("funding bundles", Ordered, func() { Expect(s.App().FundersKeeper.GetTotalActiveFunding(s.Ctx(), fundingState.PoolId).IsZero()).To(BeTrue()) Expect(fundingState.ActiveFunderAddresses).To(HaveLen(0)) }) + + It("Produce a valid bundle with only one funder and multiple coins", func() { + // ARRANGE + s.RunTxFundersSuccess(&funderstypes.MsgFundPool{ + Creator: i.ALICE, + PoolId: 0, + Amounts: sdk.NewCoins(i.ACoin(100*i.T_KYVE), i.BCoin(50*i.T_KYVE)), + AmountsPerBundle: sdk.NewCoins(i.ACoin(10*i.T_KYVE), i.BCoin(2*i.T_KYVE)), + }) + + s.CommitAfterSeconds(60) + + s.RunTxBundlesSuccess(&bundletypes.MsgSubmitBundleProposal{ + Creator: i.VALADDRESS_0_A, + Staker: i.STAKER_0, + PoolId: 0, + StorageId: "y62A3tfbSNcNYDGoL-eXwzyV-Zc9Q0OVtDvR1biJmNI", + DataSize: 100, + DataHash: "test_hash", + FromIndex: 0, + BundleSize: 100, + FromKey: "0", + ToKey: "99", + BundleSummary: "test_value", + }) + + s.RunTxBundlesSuccess(&bundletypes.MsgVoteBundleProposal{ + Creator: i.VALADDRESS_1_A, + Staker: i.STAKER_1, + PoolId: 0, + StorageId: "y62A3tfbSNcNYDGoL-eXwzyV-Zc9Q0OVtDvR1biJmNI", + Vote: 1, + }) + + s.CommitAfterSeconds(60) + + // ACT + s.RunTxBundlesSuccess(&bundletypes.MsgSubmitBundleProposal{ + Creator: i.VALADDRESS_1_A, + Staker: i.STAKER_1, + PoolId: 0, + StorageId: "P9edn0bjEfMU_lecFDIPLvGO2v2ltpFNUMWp5kgPddg", + DataSize: 100, + DataHash: "test_hash2", + FromIndex: 100, + BundleSize: 100, + FromKey: "100", + ToKey: "199", + BundleSummary: "test_value2", + }) + + // ASSERT + pool, _ := s.App().PoolKeeper.GetPool(s.Ctx(), 0) + + // assert if bundle go finalized + Expect(pool.TotalBundles).To(Equal(uint64(1))) + Expect(pool.CurrentKey).To(Equal("99")) + + fundingState, _ := s.App().FundersKeeper.GetFundingState(s.Ctx(), 0) + + // assert total pool funds + Expect(s.App().FundersKeeper.GetTotalActiveFunding(s.Ctx(), fundingState.PoolId).String()).To(Equal(sdk.NewCoins(i.ACoin(90*i.T_KYVE), i.BCoin(48*i.T_KYVE)).String())) + Expect(fundingState.ActiveFunderAddresses).To(HaveLen(1)) + + funding, _ := s.App().FundersKeeper.GetFunding(s.Ctx(), i.ALICE, 0) + + // assert individual funds + Expect(funding.Amounts.String()).To(Equal(sdk.NewCoins(i.ACoin(90*i.T_KYVE), i.BCoin(48*i.T_KYVE)).String())) + Expect(funding.TotalFunded.String()).To(Equal(sdk.NewCoins(i.ACoin(10*i.T_KYVE), i.BCoin(2*i.T_KYVE)).String())) + + // assert individual balances + balanceAlice := s.GetCoinsFromAddress(i.ALICE) + Expect(balanceAlice.String()).To(Equal(initialBalanceAlice.Sub(i.ACoin(100*i.T_KYVE), i.BCoin(50*i.T_KYVE)).String())) + }) + + It("Produce a valid bundle with multiple funders and multiple coins", func() { + // ARRANGE + s.RunTxFundersSuccess(&funderstypes.MsgFundPool{ + Creator: i.ALICE, + PoolId: 0, + Amounts: sdk.NewCoins(i.ACoin(100*i.T_KYVE), i.BCoin(50*i.T_KYVE)), + AmountsPerBundle: sdk.NewCoins(i.ACoin(10*i.T_KYVE), i.BCoin(2*i.T_KYVE)), + }) + + s.RunTxFundersSuccess(&funderstypes.MsgFundPool{ + Creator: i.BOB, + PoolId: 0, + Amounts: sdk.NewCoins(i.BCoin(100*i.T_KYVE), i.CCoin(200*i.T_KYVE)), + AmountsPerBundle: sdk.NewCoins(i.BCoin(10*i.T_KYVE), i.CCoin(20*i.T_KYVE)), + }) + + s.CommitAfterSeconds(60) + + s.RunTxBundlesSuccess(&bundletypes.MsgSubmitBundleProposal{ + Creator: i.VALADDRESS_0_A, + Staker: i.STAKER_0, + PoolId: 0, + StorageId: "y62A3tfbSNcNYDGoL-eXwzyV-Zc9Q0OVtDvR1biJmNI", + DataSize: 100, + DataHash: "test_hash", + FromIndex: 0, + BundleSize: 100, + FromKey: "0", + ToKey: "99", + BundleSummary: "test_value", + }) + + s.RunTxBundlesSuccess(&bundletypes.MsgVoteBundleProposal{ + Creator: i.VALADDRESS_1_A, + Staker: i.STAKER_1, + PoolId: 0, + StorageId: "y62A3tfbSNcNYDGoL-eXwzyV-Zc9Q0OVtDvR1biJmNI", + Vote: 1, + }) + + s.CommitAfterSeconds(60) + + // ACT + s.RunTxBundlesSuccess(&bundletypes.MsgSubmitBundleProposal{ + Creator: i.VALADDRESS_1_A, + Staker: i.STAKER_1, + PoolId: 0, + StorageId: "P9edn0bjEfMU_lecFDIPLvGO2v2ltpFNUMWp5kgPddg", + DataSize: 100, + DataHash: "test_hash2", + FromIndex: 100, + BundleSize: 100, + FromKey: "100", + ToKey: "199", + BundleSummary: "test_value2", + }) + + // ASSERT + pool, _ := s.App().PoolKeeper.GetPool(s.Ctx(), 0) + + // assert if bundle go finalized + Expect(pool.TotalBundles).To(Equal(uint64(1))) + Expect(pool.CurrentKey).To(Equal("99")) + + fundingState, _ := s.App().FundersKeeper.GetFundingState(s.Ctx(), 0) + + // assert total pool funds + Expect(s.App().FundersKeeper.GetTotalActiveFunding(s.Ctx(), fundingState.PoolId).String()).To(Equal(sdk.NewCoins(i.ACoin(90*i.T_KYVE), i.BCoin(138*i.T_KYVE), i.CCoin(180*i.T_KYVE)).String())) + Expect(fundingState.ActiveFunderAddresses).To(HaveLen(2)) + + fundingAlice, _ := s.App().FundersKeeper.GetFunding(s.Ctx(), i.ALICE, 0) + fundingBob, _ := s.App().FundersKeeper.GetFunding(s.Ctx(), i.BOB, 0) + + // assert individual funds + Expect(fundingAlice.Amounts.String()).To(Equal(sdk.NewCoins(i.ACoin(90*i.T_KYVE), i.BCoin(48*i.T_KYVE)).String())) + Expect(fundingAlice.TotalFunded.String()).To(Equal(sdk.NewCoins(i.ACoin(10*i.T_KYVE), i.BCoin(2*i.T_KYVE)).String())) + Expect(fundingBob.Amounts.String()).To(Equal(sdk.NewCoins(i.BCoin(90*i.T_KYVE), i.CCoin(180*i.T_KYVE)).String())) + Expect(fundingBob.TotalFunded.String()).To(Equal(sdk.NewCoins(i.BCoin(10*i.T_KYVE), i.CCoin(20*i.T_KYVE)).String())) + + // assert individual balances + balanceAlice := s.GetCoinsFromAddress(i.ALICE) + Expect(balanceAlice.String()).To(Equal(initialBalanceAlice.Sub(i.ACoin(100*i.T_KYVE), i.BCoin(50*i.T_KYVE)).String())) + + balanceBob := s.GetCoinsFromAddress(i.BOB) + Expect(balanceBob.String()).To(Equal(initialBalanceBob.Sub(i.BCoin(100*i.T_KYVE), i.CCoin(200*i.T_KYVE)).String())) + }) + + It("Produce a valid bundle although the only funder can not pay for the full bundle reward", func() { + // ARRANGE + s.RunTxFundersSuccess(&funderstypes.MsgFundPool{ + Creator: i.ALICE, + PoolId: 0, + Amounts: sdk.NewCoins(i.ACoin(100*i.T_KYVE), i.BCoin(50*i.T_KYVE)), + AmountsPerBundle: sdk.NewCoins(i.ACoin(10*i.T_KYVE), i.BCoin(100*i.T_KYVE)), + }) + + s.CommitAfterSeconds(60) + + s.RunTxBundlesSuccess(&bundletypes.MsgSubmitBundleProposal{ + Creator: i.VALADDRESS_0_A, + Staker: i.STAKER_0, + PoolId: 0, + StorageId: "y62A3tfbSNcNYDGoL-eXwzyV-Zc9Q0OVtDvR1biJmNI", + DataSize: 100, + DataHash: "test_hash", + FromIndex: 0, + BundleSize: 100, + FromKey: "0", + ToKey: "99", + BundleSummary: "test_value", + }) + + s.RunTxBundlesSuccess(&bundletypes.MsgVoteBundleProposal{ + Creator: i.VALADDRESS_1_A, + Staker: i.STAKER_1, + PoolId: 0, + StorageId: "y62A3tfbSNcNYDGoL-eXwzyV-Zc9Q0OVtDvR1biJmNI", + Vote: 1, + }) + + s.CommitAfterSeconds(60) + + // ACT + s.RunTxBundlesSuccess(&bundletypes.MsgSubmitBundleProposal{ + Creator: i.VALADDRESS_1_A, + Staker: i.STAKER_1, + PoolId: 0, + StorageId: "P9edn0bjEfMU_lecFDIPLvGO2v2ltpFNUMWp5kgPddg", + DataSize: 100, + DataHash: "test_hash2", + FromIndex: 100, + BundleSize: 100, + FromKey: "100", + ToKey: "199", + BundleSummary: "test_value2", + }) + + // ASSERT + pool, _ := s.App().PoolKeeper.GetPool(s.Ctx(), 0) + + // assert if bundle go finalized + Expect(pool.TotalBundles).To(Equal(uint64(1))) + Expect(pool.CurrentKey).To(Equal("99")) + + fundingState, _ := s.App().FundersKeeper.GetFundingState(s.Ctx(), 0) + + // assert total pool funds + Expect(s.App().FundersKeeper.GetTotalActiveFunding(s.Ctx(), fundingState.PoolId).String()).To(Equal(sdk.NewCoins(i.ACoin(90 * i.T_KYVE)).String())) + Expect(fundingState.ActiveFunderAddresses).To(HaveLen(1)) + + fundingAlice, _ := s.App().FundersKeeper.GetFunding(s.Ctx(), i.ALICE, 0) + + // assert individual funds + Expect(fundingAlice.Amounts.String()).To(Equal(sdk.NewCoins(i.ACoin(90 * i.T_KYVE)).String())) + Expect(fundingAlice.TotalFunded.String()).To(Equal(sdk.NewCoins(i.ACoin(10*i.T_KYVE), i.BCoin(50*i.T_KYVE)).String())) + + // assert individual balances + balanceAlice := s.GetCoinsFromAddress(i.ALICE) + Expect(balanceAlice.String()).To(Equal(initialBalanceAlice.Sub(i.ACoin(100*i.T_KYVE), i.BCoin(50*i.T_KYVE)).String())) + }) }) diff --git a/x/bundles/keeper/keeper_suite_inflation_splitting_test.go b/x/bundles/keeper/keeper_suite_inflation_splitting_test.go index f136578a..27d17a42 100644 --- a/x/bundles/keeper/keeper_suite_inflation_splitting_test.go +++ b/x/bundles/keeper/keeper_suite_inflation_splitting_test.go @@ -9,7 +9,7 @@ import ( pooltypes "github.com/KYVENetwork/chain/x/pool/types" stakertypes "github.com/KYVENetwork/chain/x/stakers/types" teamTypes "github.com/KYVENetwork/chain/x/team/types" - "github.com/cosmos/cosmos-sdk/types" + sdk "github.com/cosmos/cosmos-sdk/types" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) @@ -34,6 +34,10 @@ TEST CASES - inflation splitting * Produce a valid bundle with some insufficient funders and 10% inflation splitting * Produce a valid bundle with some insufficient funders and 100% inflation splitting +* Produce a valid bundle with multiple coins funded and 0% inflation splitting +* Produce a valid bundle with multiple coins funded and 10% inflation splitting +* Produce a valid bundle with multiple coins funded and 100% inflation splitting + * Produce a valid bundle with no funders, 0% inflation splitting and 0 inflation-share-weight * Produce a valid bundle with no funders, 10% inflation splitting and pool-0 = 0.1 weight and pool-1 = 1.0 weight * Produce a valid bundle with no funders, 10% inflation splitting and pool-0 = 1.0 weight and pool-1 = 1.0 weight @@ -43,6 +47,8 @@ TEST CASES - inflation splitting var _ = Describe("inflation splitting", Ordered, func() { var s *i.KeeperTestSuite + amountPerBundle := int64(5_000) + BeforeEach(func() { // init new clean chain s = i.NewCleanChain() @@ -62,16 +68,43 @@ var _ = Describe("inflation splitting", Ordered, func() { MaxBundleSize: 100, Version: "0.0.0", Binaries: "{}", - StorageProviderId: 2, + StorageProviderId: 1, CompressionId: 1, } s.RunTxPoolSuccess(msg) - params := funderstypes.DefaultParams() - params.CoinWhitelist[0].MinFundingAmount = 100 - params.CoinWhitelist[0].MinFundingAmountPerBundle = 1_000 - params.MinFundingMultiple = 0 - s.App().FundersKeeper.SetParams(s.Ctx(), params) + // set storage cost to 0.5 + bundleParams := s.App().BundlesKeeper.GetParams(s.Ctx()) + bundleParams.StorageCosts = append(bundleParams.StorageCosts, bundletypes.StorageCost{StorageProviderId: 1, Cost: math.LegacyMustNewDecFromStr("0.5")}) + s.App().BundlesKeeper.SetParams(s.Ctx(), bundleParams) + + // set funders params + s.App().FundersKeeper.SetParams(s.Ctx(), funderstypes.NewParams([]*funderstypes.WhitelistCoinEntry{ + { + CoinDenom: globalTypes.Denom, + MinFundingAmount: 100, + MinFundingAmountPerBundle: uint64(amountPerBundle), + CoinWeight: math.LegacyNewDec(1), + }, + { + CoinDenom: i.A_DENOM, + MinFundingAmount: 10 * i.KYVE, + MinFundingAmountPerBundle: uint64(amountPerBundle), + CoinWeight: math.LegacyNewDec(1), + }, + { + CoinDenom: i.B_DENOM, + MinFundingAmount: 10 * i.KYVE, + MinFundingAmountPerBundle: uint64(amountPerBundle), + CoinWeight: math.LegacyNewDec(2), + }, + { + CoinDenom: i.C_DENOM, + MinFundingAmount: 10 * i.KYVE, + MinFundingAmountPerBundle: uint64(amountPerBundle), + CoinWeight: math.LegacyNewDec(3), + }, + }, 0)) // create funders s.RunTxFundersSuccess(&funderstypes.MsgCreateFunder{ @@ -161,6 +194,7 @@ var _ = Describe("inflation splitting", Ordered, func() { s.CommitAfterSeconds(60) b1 := s.GetBalanceFromPool(0) + c1 := s.GetCoinsFromCommunityPool() // ACT s.RunTxBundlesSuccess(&bundletypes.MsgSubmitBundleProposal{ @@ -199,6 +233,10 @@ var _ = Describe("inflation splitting", Ordered, func() { fundingState, _ := s.App().FundersKeeper.GetFundingState(s.Ctx(), 0) + // assert treasury payout since inflation is zero here + c2 := s.GetCoinsFromCommunityPool() + Expect(c2.Sub(c1...)).To(BeEmpty()) + // assert total pool funds Expect(s.App().FundersKeeper.GetTotalActiveFunding(s.Ctx(), fundingState.PoolId)).To(BeZero()) Expect(fundingState.ActiveFunderAddresses).To(BeEmpty()) @@ -274,21 +312,16 @@ var _ = Describe("inflation splitting", Ordered, func() { // assert bundle reward uploader, _ := s.App().StakersKeeper.GetStaker(s.Ctx(), i.STAKER_0) - // the total payout is here just the inflation payout - totalPayout := payout - - networkFee := s.App().BundlesKeeper.GetNetworkFee(s.Ctx()) - treasuryReward := uint64(math.LegacyNewDec(int64(totalPayout)).Mul(networkFee).TruncateInt64()) - storageReward := uint64(s.App().BundlesKeeper.GetStorageCost(s.Ctx(), pool.GetCurrentStorageProviderId()).MulInt64(100).TruncateInt64()) - totalUploaderReward := totalPayout - treasuryReward - storageReward - - uploaderPayoutReward := uint64(math.LegacyNewDec(int64(totalUploaderReward)).Mul(uploader.Commission).TruncateInt64()) - uploaderDelegationReward := totalUploaderReward - uploaderPayoutReward - - // assert commission rewards - Expect(uploader.CommissionRewards.AmountOf(globalTypes.Denom).Uint64()).To(Equal(uploaderPayoutReward + storageReward)) - // assert uploader self delegation rewards - Expect(s.App().DelegationKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_0, i.STAKER_0).AmountOf(globalTypes.Denom).Uint64()).To(Equal(uploaderDelegationReward)) + // assert commission rewards (here we round down since the result of commission rewards gets truncated) + // (total_bundle_payout - treasury_reward - storage_cost) * (1 - commission) + // storage_cost = byte_size * usd_per_byte / len(coins) * coin_weight + // (2471669 - (2471669 * 0.01) - _((100 * 0.5) / (1 * 1))_) * 0.1 + _((100 * 0.5) / (1 * 1))_ + Expect(uploader.CommissionRewards.String()).To(Equal(i.KYVECoins(244_740).String())) + // assert uploader self delegation rewards (here we round up since the result of delegation rewards is the remainder minus the truncated commission rewards) + // (total_bundle_payout - treasury_reward - storage_cost) * commission + storage_cost + // storage_cost = byte_size * usd_per_byte / len(coins) * coin_weight + // (2471669 - (2471669 * 0.01) - _((100 * 0.5) / (1 * 1))_) * (1 - 0.1) + Expect(s.App().DelegationKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_0, i.STAKER_0).String()).To(Equal(i.KYVECoins(2_202_213).String())) fundingState, _ := s.App().FundersKeeper.GetFundingState(s.Ctx(), 0) @@ -300,7 +333,7 @@ var _ = Describe("inflation splitting", Ordered, func() { It("Produce a valid bundle with no funders and 100% inflation splitting", func() { // ARRANGE params := pooltypes.DefaultParams() - params.ProtocolInflationShare = math.LegacyMustNewDecFromStr("0.1") + params.ProtocolInflationShare = math.LegacyMustNewDecFromStr("1") params.PoolInflationPayoutRate = math.LegacyMustNewDecFromStr("0.2") s.App().PoolKeeper.SetParams(s.Ctx(), params) @@ -361,27 +394,19 @@ var _ = Describe("inflation splitting", Ordered, func() { b2 := s.GetBalanceFromPool(0) Expect(b1).To(BeNumerically(">", b2)) + // inflation payout is 49433483tkyve payout := uint64(math.LegacyNewDec(int64(b1)).Mul(s.App().PoolKeeper.GetPoolInflationPayoutRate(s.Ctx())).TruncateInt64()) Expect(b1 - b2).To(Equal(payout)) // assert bundle reward uploader, _ := s.App().StakersKeeper.GetStaker(s.Ctx(), i.STAKER_0) - // the total payout is here just the inflation payout - totalPayout := payout - - networkFee := s.App().BundlesKeeper.GetNetworkFee(s.Ctx()) - treasuryReward := uint64(math.LegacyNewDec(int64(totalPayout)).Mul(networkFee).TruncateInt64()) - storageReward := uint64(s.App().BundlesKeeper.GetStorageCost(s.Ctx(), pool.GetCurrentStorageProviderId()).MulInt64(100).TruncateInt64()) - totalUploaderReward := totalPayout - treasuryReward - storageReward - - uploaderPayoutReward := uint64(math.LegacyNewDec(int64(totalUploaderReward)).Mul(uploader.Commission).TruncateInt64()) - uploaderDelegationReward := totalUploaderReward - uploaderPayoutReward - - // assert commission rewards - Expect(uploader.CommissionRewards.AmountOf(globalTypes.Denom).Uint64()).To(Equal(uploaderPayoutReward + storageReward)) - // assert uploader self delegation rewards - Expect(s.App().DelegationKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_0, i.STAKER_0).AmountOf(globalTypes.Denom).Uint64()).To(Equal(uploaderDelegationReward)) + // assert commission rewards (here we round down since the result of commission rewards gets truncated) + // (49433483 - (49433483 * 0.01) - _((100 * 0.5) / (1 * 1))_) * 0.1 + _((100 * 0.5) / (1 * 1))_ + Expect(uploader.CommissionRewards.String()).To(Equal(i.KYVECoins(4_893_959).String())) + // assert uploader self delegation rewards (here we round up since the result of delegation rewards is the remainder minus the truncated commission rewards) + // (49433483 - (49433483 * 0.01) - _((100 * 0.5) / (1 * 1))_) * (1 - 0.1) + Expect(s.App().DelegationKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_0, i.STAKER_0).String()).To(Equal(i.KYVECoins(44_045_190).String())) fundingState, _ := s.App().FundersKeeper.GetFundingState(s.Ctx(), 0) @@ -406,14 +431,14 @@ var _ = Describe("inflation splitting", Ordered, func() { Creator: i.ALICE, PoolId: 0, Amounts: i.KYVECoins(100 * i.T_KYVE), - AmountsPerBundle: i.KYVECoins(5_000), + AmountsPerBundle: i.KYVECoins(amountPerBundle), }) s.RunTxFundersSuccess(&funderstypes.MsgFundPool{ Creator: i.BOB, PoolId: 0, Amounts: i.KYVECoins(100 * i.T_KYVE), - AmountsPerBundle: i.KYVECoins(5_000), + AmountsPerBundle: i.KYVECoins(amountPerBundle), }) s.RunTxBundlesSuccess(&bundletypes.MsgSubmitBundleProposal{ @@ -441,6 +466,7 @@ var _ = Describe("inflation splitting", Ordered, func() { s.CommitAfterSeconds(60) b1 := s.GetBalanceFromPool(0) + c1 := s.GetCoinsFromCommunityPool() // ACT s.RunTxBundlesSuccess(&bundletypes.MsgSubmitBundleProposal{ @@ -469,28 +495,26 @@ var _ = Describe("inflation splitting", Ordered, func() { Expect(b1).To(BeZero()) Expect(b2).To(BeZero()) - // assert bundle reward + // check uploader rewards + // we assert no kyve coins here since inflation is zero uploader, _ := s.App().StakersKeeper.GetStaker(s.Ctx(), i.STAKER_0) - // the total payout is the inflation share weight because the funding is sufficient - // and there is no additional inflation - totalPayout := pool.InflationShareWeight - - networkFee := s.App().BundlesKeeper.GetNetworkFee(s.Ctx()) - treasuryReward := totalPayout.Mul(networkFee) - storageReward := s.App().BundlesKeeper.GetStorageCost(s.Ctx(), pool.GetCurrentStorageProviderId()).MulInt64(100) - totalUploaderReward := totalPayout.Sub(treasuryReward).Sub(storageReward) - - uploaderPayoutReward := totalUploaderReward.Mul(uploader.Commission) - uploaderDelegationReward := totalUploaderReward.Sub(uploaderPayoutReward) - - // assert commission rewards - Expect(uploader.CommissionRewards.AmountOf(globalTypes.Denom).ToLegacyDec()).To(Equal(uploaderPayoutReward.Add(storageReward))) - // assert uploader self delegation rewards - Expect(s.App().DelegationKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_0, i.STAKER_0).AmountOf(globalTypes.Denom).ToLegacyDec()).To(Equal(uploaderDelegationReward)) + // assert commission rewards (here we round down since the result of commission rewards gets truncated) + // (10_000 - (10_000 * 0.01) - _((100 * 0.5) / (1 * 1))_) * 0.1 + _((100 * 0.5) / (1 * 1))_ + Expect(uploader.CommissionRewards.String()).To(Equal(i.KYVECoins(1035).String())) + // assert uploader self delegation rewards (here we round up since the result of delegation rewards is the remainder minus the truncated commission rewards) + // (10_000 - (10_000 * 0.01) - _((100 * 0.5) / (1 * 1))_) * (1 - 0.1) + Expect(s.App().DelegationKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_0, i.STAKER_0).String()).To(Equal(i.KYVECoins(8865).String())) fundingState, _ := s.App().FundersKeeper.GetFundingState(s.Ctx(), 0) + // assert treasury payout since inflation is zero here + c2 := s.GetCoinsFromCommunityPool() + Expect(c2.Sub(c1...).AmountOf(globalTypes.Denom).Uint64()).To(Equal(uint64(100))) + Expect(c2.Sub(c1...).AmountOf(i.A_DENOM).Uint64()).To(BeZero()) + Expect(c2.Sub(c1...).AmountOf(i.B_DENOM).Uint64()).To(BeZero()) + Expect(c2.Sub(c1...).AmountOf(i.C_DENOM).Uint64()).To(BeZero()) + // assert total pool funds Expect(s.App().FundersKeeper.GetTotalActiveFunding(s.Ctx(), fundingState.PoolId)[0].Amount.Uint64()).To(Equal(200*i.KYVE - 10_000)) Expect(fundingState.ActiveFunderAddresses).To(HaveLen(2)) @@ -512,14 +536,14 @@ var _ = Describe("inflation splitting", Ordered, func() { Creator: i.ALICE, PoolId: 0, Amounts: i.KYVECoins(100 * i.T_KYVE), - AmountsPerBundle: i.KYVECoins(5_000), + AmountsPerBundle: i.KYVECoins(amountPerBundle), }) s.RunTxFundersSuccess(&funderstypes.MsgFundPool{ Creator: i.BOB, PoolId: 0, Amounts: i.KYVECoins(100 * i.T_KYVE), - AmountsPerBundle: i.KYVECoins(5_000), + AmountsPerBundle: i.KYVECoins(amountPerBundle), }) s.RunTxBundlesSuccess(&bundletypes.MsgSubmitBundleProposal{ @@ -546,7 +570,7 @@ var _ = Describe("inflation splitting", Ordered, func() { s.CommitAfterSeconds(60) - b1 := math.LegacyNewDec(int64(s.GetBalanceFromPool(0))) + b1 := s.GetBalanceFromPool(0) // ACT s.RunTxBundlesSuccess(&bundletypes.MsgSubmitBundleProposal{ @@ -571,30 +595,22 @@ var _ = Describe("inflation splitting", Ordered, func() { Expect(pool.CurrentKey).To(Equal("99")) // assert pool balance - b2 := math.LegacyNewDec(int64(s.GetBalanceFromPool(0))) - Expect(b1.TruncateInt64()).To(BeNumerically(">", b2.TruncateInt64())) + b2 := s.GetBalanceFromPool(0) + Expect(b1).To(BeNumerically(">", b2)) - payout := b1.Mul(s.App().PoolKeeper.GetPoolInflationPayoutRate(s.Ctx())).TruncateDec() - Expect(b1.Sub(b2)).To(Equal(payout)) + // inflation payout is 7415009tkyve + payout := uint64(math.LegacyNewDec(int64(b1)).Mul(s.App().PoolKeeper.GetPoolInflationPayoutRate(s.Ctx())).TruncateInt64()) + Expect(b1 - b2).To(Equal(payout)) // assert bundle reward uploader, _ := s.App().StakersKeeper.GetStaker(s.Ctx(), i.STAKER_0) - // the total payout is the inflation share weight plus the inflation payout - totalPayout := pool.InflationShareWeight.Add(payout) - - networkFee := s.App().BundlesKeeper.GetNetworkFee(s.Ctx()) - treasuryReward := totalPayout.Mul(networkFee).TruncateDec() - storageReward := s.App().BundlesKeeper.GetStorageCost(s.Ctx(), pool.GetCurrentStorageProviderId()).MulInt64(100).TruncateDec() - totalUploaderReward := totalPayout.Sub(treasuryReward).Sub(storageReward) - - uploaderPayoutReward := totalUploaderReward.Mul(uploader.Commission).TruncateDec() - uploaderDelegationReward := totalUploaderReward.Sub(uploaderPayoutReward) - - // assert commission rewards - Expect(uploader.CommissionRewards.AmountOf(globalTypes.Denom).ToLegacyDec()).To(Equal(uploaderPayoutReward.Add(storageReward))) - // assert uploader self delegation rewards - Expect(s.App().DelegationKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_0, i.STAKER_0).AmountOf(globalTypes.Denom).ToLegacyDec()).To(Equal(uploaderDelegationReward)) + // assert commission rewards (here we round down since the result of commission rewards gets truncated) + // (7_415_009 + 10_000 - ((7_415_009 + 10_000) * 0.01) - _((100 * 0.5) / (1 * 1))_) * 0.1 + _((100 * 0.5) / (1 * 1))_ + Expect(uploader.CommissionRewards.String()).To(Equal(i.KYVECoins(735_120).String())) + // assert uploader self delegation rewards (here we round up since the result of delegation rewards is the remainder minus the truncated commission rewards) + // (7_415_009 + 10_000 - ((7_415_009 + 10_000) * 0.01) - _((100 * 0.5) / (1 * 1))_) * (1 - 0.1) + Expect(s.App().DelegationKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_0, i.STAKER_0).String()).To(Equal(i.KYVECoins(6_615_639).String())) fundingState, _ := s.App().FundersKeeper.GetFundingState(s.Ctx(), 0) @@ -653,7 +669,7 @@ var _ = Describe("inflation splitting", Ordered, func() { s.CommitAfterSeconds(60) - b1 := math.LegacyNewDec(int64(s.GetBalanceFromPool(0))) + b1 := s.GetBalanceFromPool(0) // ACT s.RunTxBundlesSuccess(&bundletypes.MsgSubmitBundleProposal{ @@ -678,30 +694,22 @@ var _ = Describe("inflation splitting", Ordered, func() { Expect(pool.CurrentKey).To(Equal("99")) // assert pool balance - b2 := math.LegacyNewDec(int64(s.GetBalanceFromPool(0))) - Expect(b1.TruncateInt64()).To(BeNumerically(">", b2.TruncateInt64())) + b2 := s.GetBalanceFromPool(0) + Expect(b1).To(BeNumerically(">", b2)) - payout := b1.Mul(s.App().PoolKeeper.GetPoolInflationPayoutRate(s.Ctx())).TruncateDec() - Expect(b1.Sub(b2)).To(Equal(payout)) + // inflation payout is 24716741tkyve + payout := uint64(math.LegacyNewDec(int64(b1)).Mul(s.App().PoolKeeper.GetPoolInflationPayoutRate(s.Ctx())).TruncateInt64()) + Expect(b1 - b2).To(Equal(payout)) // assert bundle reward uploader, _ := s.App().StakersKeeper.GetStaker(s.Ctx(), i.STAKER_0) - // the total payout is the inflation share weight plus the inflation payout - totalPayout := pool.InflationShareWeight.Add(payout) - - networkFee := s.App().BundlesKeeper.GetNetworkFee(s.Ctx()) - treasuryReward := totalPayout.Mul(networkFee).TruncateDec() - storageReward := s.App().BundlesKeeper.GetStorageCost(s.Ctx(), pool.GetCurrentStorageProviderId()).MulInt64(100).TruncateDec() - totalUploaderReward := totalPayout.Sub(treasuryReward).Sub(storageReward) - - uploaderPayoutReward := totalUploaderReward.Mul(uploader.Commission).TruncateDec() - uploaderDelegationReward := totalUploaderReward.Sub(uploaderPayoutReward) - - // assert commission rewards - Expect(uploader.CommissionRewards.AmountOf(globalTypes.Denom).ToLegacyDec()).To(Equal(uploaderPayoutReward.Add(storageReward))) - // assert uploader self delegation rewards - Expect(s.App().DelegationKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_0, i.STAKER_0).AmountOf(globalTypes.Denom).ToLegacyDec()).To(Equal(uploaderDelegationReward)) + // assert commission rewards (here we round down since the result of commission rewards gets truncated) + // (2_471_6741 + 10_000 - ((2_471_6741 + 10_000) * 0.01) - _((100 * 0.5) / (1 * 1))_) * 0.1 + _((100 * 0.5) / (1 * 1))_ + Expect(uploader.CommissionRewards.String()).To(Equal(i.KYVECoins(2_447_992).String())) + // assert uploader self delegation rewards (here we round up since the result of delegation rewards is the remainder minus the truncated commission rewards) + // (2_471_6741 + 10_000 - ((2_471_6741 + 10_000) * 0.01) - _((100 * 0.5) / (1 * 1))_) * (1 - 0.1) + Expect(s.App().DelegationKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_0, i.STAKER_0).String()).To(Equal(i.KYVECoins(22_031_482).String())) fundingState, _ := s.App().FundersKeeper.GetFundingState(s.Ctx(), 0) @@ -726,14 +734,14 @@ var _ = Describe("inflation splitting", Ordered, func() { Creator: i.ALICE, PoolId: 0, Amounts: i.KYVECoins(100), - AmountsPerBundle: i.KYVECoins(5_000), + AmountsPerBundle: i.KYVECoins(amountPerBundle), }) s.RunTxFundersSuccess(&funderstypes.MsgFundPool{ Creator: i.BOB, PoolId: 0, Amounts: i.KYVECoins(200), - AmountsPerBundle: i.KYVECoins(5_000), + AmountsPerBundle: i.KYVECoins(amountPerBundle), }) s.RunTxBundlesSuccess(&bundletypes.MsgSubmitBundleProposal{ @@ -761,6 +769,7 @@ var _ = Describe("inflation splitting", Ordered, func() { s.CommitAfterSeconds(60) b1 := s.GetBalanceFromPool(0) + c1 := s.GetCoinsFromCommunityPool() // ACT s.RunTxBundlesSuccess(&bundletypes.MsgSubmitBundleProposal{ @@ -792,24 +801,22 @@ var _ = Describe("inflation splitting", Ordered, func() { // assert bundle reward uploader, _ := s.App().StakersKeeper.GetStaker(s.Ctx(), i.STAKER_0) - // the total payout is the total funds - totalPayout := math.LegacyNewDec(300) - - networkFee := s.App().BundlesKeeper.GetNetworkFee(s.Ctx()) - treasuryReward := totalPayout.Mul(networkFee).TruncateDec() - storageReward := s.App().BundlesKeeper.GetStorageCost(s.Ctx(), pool.GetCurrentStorageProviderId()).MulInt64(100).TruncateDec() - totalUploaderReward := totalPayout.Sub(treasuryReward).Sub(storageReward) - - uploaderPayoutReward := totalUploaderReward.Mul(uploader.Commission).TruncateDec() - uploaderDelegationReward := totalUploaderReward.Sub(uploaderPayoutReward) - - // assert commission rewards - Expect(uploader.CommissionRewards.AmountOf(globalTypes.Denom).ToLegacyDec()).To(Equal(uploaderPayoutReward.Add(storageReward))) - // assert uploader self delegation rewards - Expect(s.App().DelegationKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_0, i.STAKER_0).AmountOf(globalTypes.Denom).ToLegacyDec()).To(Equal(uploaderDelegationReward)) + // assert commission rewards (here we round down since the result of commission rewards gets truncated) + // (300 - (300 * 0.01) - _((100 * 0.5) / (1 * 1))_) * 0.1 + _((100 * 0.5) / (1 * 1))_ + Expect(uploader.CommissionRewards.String()).To(Equal(i.KYVECoins(74).String())) + // assert uploader self delegation rewards (here we round up since the result of delegation rewards is the remainder minus the truncated commission rewards) + // (300 - (300 * 0.01) - _((100 * 0.5) / (1 * 1))_) * (1 - 0.1) + Expect(s.App().DelegationKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_0, i.STAKER_0).String()).To(Equal(i.KYVECoins(223).String())) fundingState, _ := s.App().FundersKeeper.GetFundingState(s.Ctx(), 0) + // assert treasury payout since inflation is zero here + c2 := s.GetCoinsFromCommunityPool() + Expect(c2.Sub(c1...).AmountOf(globalTypes.Denom).Uint64()).To(Equal(uint64(3))) + Expect(c2.Sub(c1...).AmountOf(i.A_DENOM).Uint64()).To(BeZero()) + Expect(c2.Sub(c1...).AmountOf(i.B_DENOM).Uint64()).To(BeZero()) + Expect(c2.Sub(c1...).AmountOf(i.C_DENOM).Uint64()).To(BeZero()) + // assert total pool funds Expect(s.App().FundersKeeper.GetTotalActiveFunding(s.Ctx(), fundingState.PoolId).IsZero()).To(BeTrue()) Expect(fundingState.ActiveFunderAddresses).To(BeEmpty()) @@ -831,14 +838,14 @@ var _ = Describe("inflation splitting", Ordered, func() { Creator: i.ALICE, PoolId: 0, Amounts: i.KYVECoins(100), - AmountsPerBundle: i.KYVECoins(5_000), + AmountsPerBundle: i.KYVECoins(amountPerBundle), }) s.RunTxFundersSuccess(&funderstypes.MsgFundPool{ Creator: i.BOB, PoolId: 0, Amounts: i.KYVECoins(200), - AmountsPerBundle: i.KYVECoins(5_000), + AmountsPerBundle: i.KYVECoins(amountPerBundle), }) s.RunTxBundlesSuccess(&bundletypes.MsgSubmitBundleProposal{ @@ -865,7 +872,7 @@ var _ = Describe("inflation splitting", Ordered, func() { s.CommitAfterSeconds(60) - b1 := math.LegacyNewDec(int64(s.GetBalanceFromPool(0))) + b1 := s.GetBalanceFromPool(0) // ACT s.RunTxBundlesSuccess(&bundletypes.MsgSubmitBundleProposal{ @@ -890,30 +897,22 @@ var _ = Describe("inflation splitting", Ordered, func() { Expect(pool.CurrentKey).To(Equal("99")) // assert pool balance - b2 := math.LegacyNewDec(int64(s.GetBalanceFromPool(0))) - Expect(b1.TruncateInt64()).To(BeNumerically(">", b2.TruncateInt64())) + b2 := s.GetBalanceFromPool(0) + Expect(b1).To(BeNumerically(">", b2)) - payout := b1.Mul(s.App().PoolKeeper.GetPoolInflationPayoutRate(s.Ctx())).TruncateDec() - Expect(b1.Sub(b2)).To(Equal(payout)) + // inflation payout is 7_415_009tkyve + payout := uint64(math.LegacyNewDec(int64(b1)).Mul(s.App().PoolKeeper.GetPoolInflationPayoutRate(s.Ctx())).TruncateInt64()) + Expect(b1 - b2).To(Equal(payout)) // assert bundle reward uploader, _ := s.App().StakersKeeper.GetStaker(s.Ctx(), i.STAKER_0) - // the total payout is the inflation share weight plus the inflation payout - totalPayout := payout.Add(math.LegacyNewDec(300)) - - networkFee := s.App().BundlesKeeper.GetNetworkFee(s.Ctx()) - treasuryReward := totalPayout.Mul(networkFee).TruncateDec() - storageReward := s.App().BundlesKeeper.GetStorageCost(s.Ctx(), pool.GetCurrentStorageProviderId()).MulInt64(100).TruncateDec() - totalUploaderReward := totalPayout.Sub(treasuryReward).Sub(storageReward) - - uploaderPayoutReward := totalUploaderReward.Mul(uploader.Commission).TruncateDec() - uploaderDelegationReward := totalUploaderReward.Sub(uploaderPayoutReward) - - // assert commission rewards - Expect(uploader.CommissionRewards.AmountOf(globalTypes.Denom).ToLegacyDec()).To(Equal(uploaderPayoutReward.Add(storageReward))) - // assert uploader self delegation rewards - Expect(s.App().DelegationKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_0, i.STAKER_0).AmountOf(globalTypes.Denom).ToLegacyDec()).To(Equal(uploaderDelegationReward)) + // assert commission rewards (here we round down since the result of commission rewards gets truncated) + // (7_415_009 + 300 - ((7_415_009 + 300) * 0.01) - _((100 * 0.5) / (1 * 1))_) * 0.1 + _((100 * 0.5) / (1 * 1))_ + Expect(uploader.CommissionRewards.String()).To(Equal(i.KYVECoins(734_160).String())) + // assert uploader self delegation rewards (here we round up since the result of delegation rewards is the remainder minus the truncated commission rewards) + // (7_415_009 + 300 - ((7_415_009 + 300) * 0.01) - _((100 * 0.5) / (1 * 1))_) * (1 - 0.1) + Expect(s.App().DelegationKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_0, i.STAKER_0).String()).To(Equal(i.KYVECoins(6_606_996).String())) fundingState, _ := s.App().FundersKeeper.GetFundingState(s.Ctx(), 0) @@ -938,14 +937,14 @@ var _ = Describe("inflation splitting", Ordered, func() { Creator: i.ALICE, PoolId: 0, Amounts: i.KYVECoins(100), - AmountsPerBundle: i.KYVECoins(5_000), + AmountsPerBundle: i.KYVECoins(amountPerBundle), }) s.RunTxFundersSuccess(&funderstypes.MsgFundPool{ Creator: i.BOB, PoolId: 0, Amounts: i.KYVECoins(200), - AmountsPerBundle: i.KYVECoins(5_000), + AmountsPerBundle: i.KYVECoins(amountPerBundle), }) s.RunTxBundlesSuccess(&bundletypes.MsgSubmitBundleProposal{ @@ -972,7 +971,7 @@ var _ = Describe("inflation splitting", Ordered, func() { s.CommitAfterSeconds(60) - b1 := math.LegacyNewDec(int64(s.GetBalanceFromPool(0))) + b1 := s.GetBalanceFromPool(0) // ACT s.RunTxBundlesSuccess(&bundletypes.MsgSubmitBundleProposal{ @@ -997,30 +996,22 @@ var _ = Describe("inflation splitting", Ordered, func() { Expect(pool.CurrentKey).To(Equal("99")) // assert pool balance - b2 := math.LegacyNewDec(int64(s.GetBalanceFromPool(0))) - Expect(b1.TruncateInt64()).To(BeNumerically(">", b2.TruncateInt64())) + b2 := s.GetBalanceFromPool(0) + Expect(b1).To(BeNumerically(">", b2)) - payout := b1.Mul(s.App().PoolKeeper.GetPoolInflationPayoutRate(s.Ctx())).TruncateDec() - Expect(b1.Sub(b2)).To(Equal(payout)) + // inflation payout is 24716741tkyve + payout := uint64(math.LegacyNewDec(int64(b1)).Mul(s.App().PoolKeeper.GetPoolInflationPayoutRate(s.Ctx())).TruncateInt64()) + Expect(b1 - b2).To(Equal(payout)) // assert bundle reward uploader, _ := s.App().StakersKeeper.GetStaker(s.Ctx(), i.STAKER_0) - // the total payout is the inflation share weight plus the inflation payout - totalPayout := payout.Add(math.LegacyNewDec(300)) - - networkFee := s.App().BundlesKeeper.GetNetworkFee(s.Ctx()) - treasuryReward := totalPayout.Mul(networkFee).TruncateDec() - storageReward := s.App().BundlesKeeper.GetStorageCost(s.Ctx(), pool.GetCurrentStorageProviderId()).MulInt64(100).TruncateDec() - totalUploaderReward := totalPayout.Sub(treasuryReward).Sub(storageReward) - - uploaderPayoutReward := totalUploaderReward.Mul(uploader.Commission).TruncateDec() - uploaderDelegationReward := totalUploaderReward.Sub(uploaderPayoutReward) - - // assert commission rewards - Expect(uploader.CommissionRewards.AmountOf(globalTypes.Denom).ToLegacyDec()).To(Equal(uploaderPayoutReward.Add(storageReward))) - // assert uploader self delegation rewards - Expect(s.App().DelegationKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_0, i.STAKER_0).AmountOf(globalTypes.Denom).ToLegacyDec()).To(Equal(uploaderDelegationReward)) + // assert commission rewards (here we round down since the result of commission rewards gets truncated) + // (24_716_741 + 300 - ((24_716_741 + 300) * 0.01) - _((100 * 0.5) / (1 * 1))_) * 0.1 + _((100 * 0.5) / (1 * 1))_ + Expect(uploader.CommissionRewards.String()).To(Equal(i.KYVECoins(2_447_032).String())) + // assert uploader self delegation rewards (here we round up since the result of delegation rewards is the remainder minus the truncated commission rewards) + // (24_716_741 + 300 - ((24_716_741 + 300) * 0.01) - _((100 * 0.5) / (1 * 1))_) * (1 - 0.1) + Expect(s.App().DelegationKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_0, i.STAKER_0).String()).To(Equal(i.KYVECoins(22_022_839).String())) fundingState, _ := s.App().FundersKeeper.GetFundingState(s.Ctx(), 0) @@ -1045,14 +1036,14 @@ var _ = Describe("inflation splitting", Ordered, func() { Creator: i.ALICE, PoolId: 0, Amounts: i.KYVECoins(100 * i.T_KYVE), - AmountsPerBundle: i.KYVECoins(5_000), + AmountsPerBundle: i.KYVECoins(amountPerBundle), }) s.RunTxFundersSuccess(&funderstypes.MsgFundPool{ Creator: i.BOB, PoolId: 0, Amounts: i.KYVECoins(200), - AmountsPerBundle: i.KYVECoins(5_000), + AmountsPerBundle: i.KYVECoins(amountPerBundle), }) s.RunTxBundlesSuccess(&bundletypes.MsgSubmitBundleProposal{ @@ -1080,6 +1071,7 @@ var _ = Describe("inflation splitting", Ordered, func() { s.CommitAfterSeconds(60) b1 := s.GetBalanceFromPool(0) + c1 := s.GetCoinsFromCommunityPool() // ACT s.RunTxBundlesSuccess(&bundletypes.MsgSubmitBundleProposal{ @@ -1111,24 +1103,22 @@ var _ = Describe("inflation splitting", Ordered, func() { // assert bundle reward uploader, _ := s.App().StakersKeeper.GetStaker(s.Ctx(), i.STAKER_0) - // the total payout is the total funds - totalPayout := pool.InflationShareWeight.Quo(math.LegacyNewDec(2)).Add(math.LegacyNewDec(200)) - - networkFee := s.App().BundlesKeeper.GetNetworkFee(s.Ctx()) - treasuryReward := totalPayout.Mul(networkFee).TruncateDec() - storageReward := s.App().BundlesKeeper.GetStorageCost(s.Ctx(), pool.GetCurrentStorageProviderId()).MulInt64(100).TruncateDec() - totalUploaderReward := totalPayout.Sub(treasuryReward).Sub(storageReward) - - uploaderPayoutReward := totalUploaderReward.Mul(uploader.Commission).TruncateDec() - uploaderDelegationReward := totalUploaderReward.Sub(uploaderPayoutReward) - - // assert commission rewards - Expect(uploader.CommissionRewards.AmountOf(globalTypes.Denom).ToLegacyDec()).To(Equal(uploaderPayoutReward.Add(storageReward))) - // assert uploader self delegation rewards - Expect(s.App().DelegationKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_0, i.STAKER_0).AmountOf(globalTypes.Denom).ToLegacyDec()).To(Equal(uploaderDelegationReward)) + // assert commission rewards (here we round down since the result of commission rewards gets truncated) + // (5_000 + 200 - ((5_000 + 200) * 0.01) - _((100 * 0.5) / (1 * 1))_) * 0.1 + _((100 * 0.5) / (1 * 1))_ + Expect(uploader.CommissionRewards.String()).To(Equal(i.KYVECoins(559).String())) + // assert uploader self delegation rewards (here we round up since the result of delegation rewards is the remainder minus the truncated commission rewards) + // (5_000 + 200 - ((5_000 + 200) * 0.01) - _((100 * 0.5) / (1 * 1))_) * (1 - 0.1) + Expect(s.App().DelegationKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_0, i.STAKER_0).String()).To(Equal(i.KYVECoins(4_589).String())) fundingState, _ := s.App().FundersKeeper.GetFundingState(s.Ctx(), 0) + // assert treasury payout since inflation is zero here + c2 := s.GetCoinsFromCommunityPool() + Expect(c2.Sub(c1...).AmountOf(globalTypes.Denom).Uint64()).To(Equal(uint64(52))) + Expect(c2.Sub(c1...).AmountOf(i.A_DENOM).Uint64()).To(BeZero()) + Expect(c2.Sub(c1...).AmountOf(i.B_DENOM).Uint64()).To(BeZero()) + Expect(c2.Sub(c1...).AmountOf(i.C_DENOM).Uint64()).To(BeZero()) + // assert total pool funds Expect(s.App().FundersKeeper.GetTotalActiveFunding(s.Ctx(), fundingState.PoolId)[0].Amount.Uint64()).To(Equal(100*i.KYVE - 5_000)) Expect(fundingState.ActiveFunderAddresses).To(HaveLen(1)) @@ -1150,14 +1140,14 @@ var _ = Describe("inflation splitting", Ordered, func() { Creator: i.ALICE, PoolId: 0, Amounts: i.KYVECoins(100 * i.T_KYVE), - AmountsPerBundle: i.KYVECoins(5_000), + AmountsPerBundle: i.KYVECoins(amountPerBundle), }) s.RunTxFundersSuccess(&funderstypes.MsgFundPool{ Creator: i.BOB, PoolId: 0, Amounts: i.KYVECoins(200), - AmountsPerBundle: i.KYVECoins(5_000), + AmountsPerBundle: i.KYVECoins(amountPerBundle), }) s.RunTxBundlesSuccess(&bundletypes.MsgSubmitBundleProposal{ @@ -1184,7 +1174,7 @@ var _ = Describe("inflation splitting", Ordered, func() { s.CommitAfterSeconds(60) - b1 := math.LegacyNewDec(int64(s.GetBalanceFromPool(0))) + b1 := s.GetBalanceFromPool(0) // ACT s.RunTxBundlesSuccess(&bundletypes.MsgSubmitBundleProposal{ @@ -1209,30 +1199,22 @@ var _ = Describe("inflation splitting", Ordered, func() { Expect(pool.CurrentKey).To(Equal("99")) // assert pool balance - b2 := math.LegacyNewDec(int64(s.GetBalanceFromPool(0))) - Expect(b1.TruncateInt64()).To(BeNumerically(">", b2.TruncateInt64())) + b2 := s.GetBalanceFromPool(0) + Expect(b1).To(BeNumerically(">", b2)) - payout := b1.Mul(s.App().PoolKeeper.GetPoolInflationPayoutRate(s.Ctx())).TruncateDec() - Expect(b1.Sub(b2)).To(Equal(payout)) + // inflation payout is 7415009tkyve + payout := uint64(math.LegacyNewDec(int64(b1)).Mul(s.App().PoolKeeper.GetPoolInflationPayoutRate(s.Ctx())).TruncateInt64()) + Expect(b1 - b2).To(Equal(payout)) // assert bundle reward uploader, _ := s.App().StakersKeeper.GetStaker(s.Ctx(), i.STAKER_0) - // the total payout is the inflation share weight plus the inflation payout - totalPayout := pool.InflationShareWeight.Quo(math.LegacyNewDec(2)).Add(math.LegacyNewDec(200)).Add(payout) - - networkFee := s.App().BundlesKeeper.GetNetworkFee(s.Ctx()) - treasuryReward := totalPayout.Mul(networkFee).TruncateDec() - storageReward := s.App().BundlesKeeper.GetStorageCost(s.Ctx(), pool.GetCurrentStorageProviderId()).MulInt64(100).TruncateDec() - totalUploaderReward := totalPayout.Sub(treasuryReward).Sub(storageReward) - - uploaderPayoutReward := totalUploaderReward.Mul(uploader.Commission).TruncateDec() - uploaderDelegationReward := totalUploaderReward.Sub(uploaderPayoutReward) - - // assert commission rewards - Expect(uploader.CommissionRewards.AmountOf(globalTypes.Denom).ToLegacyDec()).To(Equal(uploaderPayoutReward.Add(storageReward))) - // assert uploader self delegation rewards - Expect(s.App().DelegationKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_0, i.STAKER_0).AmountOf(globalTypes.Denom).ToLegacyDec()).To(Equal(uploaderDelegationReward)) + // assert commission rewards (here we round down since the result of commission rewards gets truncated) + // (7_415_009 + 5_000 + 200 - ((7_415_009 + 5_000 + 200) * 0.01) - _((100 * 0.5) / (1 * 1))_) * 0.1 + _((100 * 0.5) / (1 * 1))_ + Expect(uploader.CommissionRewards.String()).To(Equal(i.KYVECoins(734_645).String())) + // assert uploader self delegation rewards (here we round up since the result of delegation rewards is the remainder minus the truncated commission rewards) + // (7_415_009 + 5_000 + 200 - ((7_415_009 + 5_000 + 200) * 0.01) - _((100 * 0.5) / (1 * 1))_) * (1 - 0.1) + Expect(s.App().DelegationKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_0, i.STAKER_0).String()).To(Equal(i.KYVECoins(6_611_362).String())) fundingState, _ := s.App().FundersKeeper.GetFundingState(s.Ctx(), 0) @@ -1241,7 +1223,7 @@ var _ = Describe("inflation splitting", Ordered, func() { Expect(fundingState.ActiveFunderAddresses).To(HaveLen(1)) }) - It("Produce a valid bundle with some insufficient funders and 10% inflation splitting", func() { + It("Produce a valid bundle with some insufficient funders and 100% inflation splitting", func() { // ARRANGE params := pooltypes.DefaultParams() params.ProtocolInflationShare = math.LegacyMustNewDecFromStr("1") @@ -1257,14 +1239,14 @@ var _ = Describe("inflation splitting", Ordered, func() { Creator: i.ALICE, PoolId: 0, Amounts: i.KYVECoins(100 * i.T_KYVE), - AmountsPerBundle: i.KYVECoins(5_000), + AmountsPerBundle: i.KYVECoins(amountPerBundle), }) s.RunTxFundersSuccess(&funderstypes.MsgFundPool{ Creator: i.BOB, PoolId: 0, Amounts: i.KYVECoins(200), - AmountsPerBundle: i.KYVECoins(5_000), + AmountsPerBundle: i.KYVECoins(amountPerBundle), }) s.RunTxBundlesSuccess(&bundletypes.MsgSubmitBundleProposal{ @@ -1291,7 +1273,7 @@ var _ = Describe("inflation splitting", Ordered, func() { s.CommitAfterSeconds(60) - b1 := math.LegacyNewDec(int64(s.GetBalanceFromPool(0))) + b1 := s.GetBalanceFromPool(0) // ACT s.RunTxBundlesSuccess(&bundletypes.MsgSubmitBundleProposal{ @@ -1316,36 +1298,352 @@ var _ = Describe("inflation splitting", Ordered, func() { Expect(pool.CurrentKey).To(Equal("99")) // assert pool balance - b2 := math.LegacyNewDec(int64(s.GetBalanceFromPool(0))) - Expect(b1.TruncateInt64()).To(BeNumerically(">", b2.TruncateInt64())) + b2 := s.GetBalanceFromPool(0) + Expect(b1).To(BeNumerically(">", b2)) - payout := b1.Mul(s.App().PoolKeeper.GetPoolInflationPayoutRate(s.Ctx())).TruncateDec() - Expect(b1.Sub(b2)).To(Equal(payout)) + // inflation payout is 24716741tkyve + payout := uint64(math.LegacyNewDec(int64(b1)).Mul(s.App().PoolKeeper.GetPoolInflationPayoutRate(s.Ctx())).TruncateInt64()) + Expect(b1 - b2).To(Equal(payout)) // assert bundle reward uploader, _ := s.App().StakersKeeper.GetStaker(s.Ctx(), i.STAKER_0) - // the total payout is the inflation share weight plus the inflation payout - totalPayout := pool.InflationShareWeight.Quo(math.LegacyNewDec(2)).Add(math.LegacyNewDec(200)).Add(payout) + // assert commission rewards (here we round down since the result of commission rewards gets truncated) + // (24_716_741 + 5_000 + 200 - ((24_716_741 + 5_000 + 200) * 0.01) - _((100 * 0.5) / (1 * 1))_) * 0.1 + _((100 * 0.5) / (1 * 1))_ + Expect(uploader.CommissionRewards.String()).To(Equal(i.KYVECoins(2_447_517).String())) + // assert uploader self delegation rewards (here we round up since the result of delegation rewards is the remainder minus the truncated commission rewards) + // (24_716_741 + 5_000 + 200 - ((24_716_741 + 5_000 + 200) * 0.01) - _((100 * 0.5) / (1 * 1))_) * (1 - 0.1) + Expect(s.App().DelegationKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_0, i.STAKER_0).String()).To(Equal(i.KYVECoins(22_027_205).String())) - networkFee := s.App().BundlesKeeper.GetNetworkFee(s.Ctx()) - treasuryReward := totalPayout.Mul(networkFee).TruncateDec() - storageReward := s.App().BundlesKeeper.GetStorageCost(s.Ctx(), pool.GetCurrentStorageProviderId()).MulInt64(100).TruncateDec() - totalUploaderReward := totalPayout.Sub(treasuryReward).Sub(storageReward) + fundingState, _ := s.App().FundersKeeper.GetFundingState(s.Ctx(), 0) - uploaderPayoutReward := totalUploaderReward.Mul(uploader.Commission).TruncateDec() - uploaderDelegationReward := totalUploaderReward.Sub(uploaderPayoutReward) + // assert total pool funds + Expect(s.App().FundersKeeper.GetTotalActiveFunding(s.Ctx(), fundingState.PoolId)[0].Amount.Uint64()).To(Equal(100*i.KYVE - 5_000)) + Expect(fundingState.ActiveFunderAddresses).To(HaveLen(1)) + }) - // assert commission rewards - Expect(uploader.CommissionRewards.AmountOf(globalTypes.Denom).ToLegacyDec()).To(Equal(uploaderPayoutReward.Add(storageReward))) - // assert uploader self delegation rewards - Expect(s.App().DelegationKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_0, i.STAKER_0).AmountOf(globalTypes.Denom).ToLegacyDec()).To(Equal(uploaderDelegationReward)) + It("Produce a valid bundle with multiple coins funded and 0% inflation splitting", func() { + // ARRANGE + params := pooltypes.DefaultParams() + params.ProtocolInflationShare = math.LegacyMustNewDecFromStr("0") + params.PoolInflationPayoutRate = math.LegacyMustNewDecFromStr("0.1") + s.App().PoolKeeper.SetParams(s.Ctx(), params) + + // mine some blocks + for i := 1; i < 100; i++ { + s.Commit() + } + + s.RunTxFundersSuccess(&funderstypes.MsgFundPool{ + Creator: i.ALICE, + PoolId: 0, + Amounts: sdk.NewCoins(i.ACoin(100*i.T_KYVE), i.BCoin(100*i.T_KYVE)), + AmountsPerBundle: sdk.NewCoins(i.ACoin(amountPerBundle), i.BCoin(2*amountPerBundle)), + }) + + s.RunTxFundersSuccess(&funderstypes.MsgFundPool{ + Creator: i.BOB, + PoolId: 0, + Amounts: sdk.NewCoins(i.ACoin(100*i.T_KYVE), i.BCoin(100*i.T_KYVE)), + AmountsPerBundle: sdk.NewCoins(i.ACoin(amountPerBundle), i.BCoin(2*amountPerBundle)), + }) + + s.RunTxBundlesSuccess(&bundletypes.MsgSubmitBundleProposal{ + Creator: i.VALADDRESS_0_A, + Staker: i.STAKER_0, + PoolId: 0, + StorageId: "y62A3tfbSNcNYDGoL-eXwzyV-Zc9Q0OVtDvR1biJmNI", + DataSize: 100, + DataHash: "test_hash", + FromIndex: 0, + BundleSize: 100, + FromKey: "0", + ToKey: "99", + BundleSummary: "test_value", + }) + + s.RunTxBundlesSuccess(&bundletypes.MsgVoteBundleProposal{ + Creator: i.VALADDRESS_1_A, + Staker: i.STAKER_1, + PoolId: 0, + StorageId: "y62A3tfbSNcNYDGoL-eXwzyV-Zc9Q0OVtDvR1biJmNI", + Vote: 1, + }) + + s.CommitAfterSeconds(60) + + b1 := s.GetBalanceFromPool(0) + c1 := s.GetCoinsFromCommunityPool() + + // ACT + s.RunTxBundlesSuccess(&bundletypes.MsgSubmitBundleProposal{ + Creator: i.VALADDRESS_1_A, + Staker: i.STAKER_1, + PoolId: 0, + StorageId: "P9edn0bjEfMU_lecFDIPLvGO2v2ltpFNUMWp5kgPddg", + DataSize: 100, + DataHash: "test_hash2", + FromIndex: 100, + BundleSize: 100, + FromKey: "100", + ToKey: "199", + BundleSummary: "test_value2", + }) + + // ASSERT + pool, _ := s.App().PoolKeeper.GetPool(s.Ctx(), 0) + + // assert if bundle go finalized + Expect(pool.TotalBundles).To(Equal(uint64(1))) + Expect(pool.CurrentKey).To(Equal("99")) + + // assert pool balance + b2 := s.GetBalanceFromPool(0) + Expect(b1).To(BeZero()) + Expect(b2).To(BeZero()) + + // check uploader rewards + // we assert no kyve coins here since inflation is zero + uploader, _ := s.App().StakersKeeper.GetStaker(s.Ctx(), i.STAKER_0) + + // assert commission rewards (here we round down since the result of commission rewards gets truncated) + // (10_000 - (10_000 * 0.01) - _((100 * 0.5) / (2 * coin_weight))_) * 0.1 + _((100 * 0.5) / (2 * coin_weight))_ + Expect(uploader.CommissionRewards.String()).To(Equal(sdk.NewCoins(i.ACoin(1012), i.BCoin(1990)).String())) + // assert uploader self delegation rewards (here we round up since the result of delegation rewards is the remainder minus the truncated commission rewards) + // (20_000 - (20_000 * 0.01) - _((100 * 0.5) / (2 * coin_weight))_) * (1 - 0.1) + Expect(s.App().DelegationKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_0, i.STAKER_0).String()).To(Equal(sdk.NewCoins(i.ACoin(8888), i.BCoin(17810)).String())) fundingState, _ := s.App().FundersKeeper.GetFundingState(s.Ctx(), 0) + // assert treasury payout + c2 := s.GetCoinsFromCommunityPool() + Expect(c2.Sub(c1...).AmountOf(i.A_DENOM).Uint64()).To(Equal(uint64(100))) + Expect(c2.Sub(c1...).AmountOf(i.B_DENOM).Uint64()).To(Equal(uint64(200))) + Expect(c2.Sub(c1...).AmountOf(i.C_DENOM).Uint64()).To(BeZero()) + // assert total pool funds - Expect(s.App().FundersKeeper.GetTotalActiveFunding(s.Ctx(), fundingState.PoolId)[0].Amount.Uint64()).To(Equal(100*i.KYVE - 5_000)) - Expect(fundingState.ActiveFunderAddresses).To(HaveLen(1)) + Expect(s.App().FundersKeeper.GetTotalActiveFunding(s.Ctx(), fundingState.PoolId).String()).To(Equal(sdk.NewCoins(i.ACoin(200*i.T_KYVE-2*amountPerBundle), i.BCoin(200*i.T_KYVE-4*amountPerBundle)).String())) + Expect(fundingState.ActiveFunderAddresses).To(HaveLen(2)) + }) + + It("Produce a valid bundle with multiple coins funded and 10% inflation splitting", func() { + // ARRANGE + params := pooltypes.DefaultParams() + params.ProtocolInflationShare = math.LegacyMustNewDecFromStr("0.1") + params.PoolInflationPayoutRate = math.LegacyMustNewDecFromStr("0.3") + s.App().PoolKeeper.SetParams(s.Ctx(), params) + + // mine some blocks + for i := 1; i < 100; i++ { + s.Commit() + } + + s.RunTxFundersSuccess(&funderstypes.MsgFundPool{ + Creator: i.ALICE, + PoolId: 0, + Amounts: sdk.NewCoins(i.ACoin(100*i.T_KYVE), i.BCoin(100*i.T_KYVE)), + AmountsPerBundle: sdk.NewCoins(i.ACoin(amountPerBundle), i.BCoin(2*amountPerBundle)), + }) + + s.RunTxFundersSuccess(&funderstypes.MsgFundPool{ + Creator: i.BOB, + PoolId: 0, + Amounts: sdk.NewCoins(i.ACoin(100*i.T_KYVE), i.BCoin(100*i.T_KYVE)), + AmountsPerBundle: sdk.NewCoins(i.ACoin(amountPerBundle), i.BCoin(2*amountPerBundle)), + }) + + s.RunTxBundlesSuccess(&bundletypes.MsgSubmitBundleProposal{ + Creator: i.VALADDRESS_0_A, + Staker: i.STAKER_0, + PoolId: 0, + StorageId: "y62A3tfbSNcNYDGoL-eXwzyV-Zc9Q0OVtDvR1biJmNI", + DataSize: 100, + DataHash: "test_hash", + FromIndex: 0, + BundleSize: 100, + FromKey: "0", + ToKey: "99", + BundleSummary: "test_value", + }) + + s.RunTxBundlesSuccess(&bundletypes.MsgVoteBundleProposal{ + Creator: i.VALADDRESS_1_A, + Staker: i.STAKER_1, + PoolId: 0, + StorageId: "y62A3tfbSNcNYDGoL-eXwzyV-Zc9Q0OVtDvR1biJmNI", + Vote: 1, + }) + + s.CommitAfterSeconds(60) + + b1 := s.GetBalanceFromPool(0) + c1 := s.GetCoinsFromCommunityPool() + + // ACT + s.RunTxBundlesSuccess(&bundletypes.MsgSubmitBundleProposal{ + Creator: i.VALADDRESS_1_A, + Staker: i.STAKER_1, + PoolId: 0, + StorageId: "P9edn0bjEfMU_lecFDIPLvGO2v2ltpFNUMWp5kgPddg", + DataSize: 100, + DataHash: "test_hash2", + FromIndex: 100, + BundleSize: 100, + FromKey: "100", + ToKey: "199", + BundleSummary: "test_value2", + }) + + // ASSERT + pool, _ := s.App().PoolKeeper.GetPool(s.Ctx(), 0) + + // assert if bundle go finalized + Expect(pool.TotalBundles).To(Equal(uint64(1))) + Expect(pool.CurrentKey).To(Equal("99")) + + // assert pool balance + b2 := s.GetBalanceFromPool(0) + Expect(b1).To(BeNumerically(">", b2)) + + // inflation payout is 7415009tkyve + payout := uint64(math.LegacyNewDec(int64(b1)).Mul(s.App().PoolKeeper.GetPoolInflationPayoutRate(s.Ctx())).TruncateInt64()) + Expect(b1 - b2).To(Equal(payout)) + + // assert bundle reward + uploader, _ := s.App().StakersKeeper.GetStaker(s.Ctx(), i.STAKER_0) + + // assert commission rewards (here we round down since the result of commission rewards gets truncated) + // for kyve coin (7_415_009 - (7_415_009 * 0.01) - _((100 * 0.5) / (3 * 1))_) * 0.1 + _((100 * 0.5) / (3 * 1))_ + // for acoin (10_000 - (10_000 * 0.01) - _((100 * 0.5) / (3 * 1))_) * 0.1 + _((100 * 0.5) / (3 * 1))_ + // for bcoin coins (20_000 - (20_000 * 0.01) - _((100 * 0.5) / (3 * 2))_) * 0.1 + _((100 * 0.5) / (3 * 2))_ + Expect(uploader.CommissionRewards.String()).To(Equal(sdk.NewCoins(i.KYVECoin(734_100), i.ACoin(1004), i.BCoin(1987)).String())) + // assert uploader self delegation rewards (here we round up since the result of delegation rewards is the remainder minus the truncated commission rewards) + // for kyve coin (7_415_009 - (7_415_009 * 0.01) - _((100 * 0.5) / (3 * 1))_) * (1 - 0.1) + // for acoin (10_000 - (10_000 * 0.01) - _((100 * 0.5) / (3 * 1))_) * (1 - 0.1) + // for bcoin (20_000 - (20_000 * 0.01) - _((100 * 0.5) / (3 * 2))_) * (1 - 0.1) + Expect(s.App().DelegationKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_0, i.STAKER_0).String()).To(Equal(sdk.NewCoins(i.KYVECoin(6_606_759), i.ACoin(8896), i.BCoin(17813)).String())) + + fundingState, _ := s.App().FundersKeeper.GetFundingState(s.Ctx(), 0) + + // assert treasury payout + c2 := s.GetCoinsFromCommunityPool() + Expect(c2.Sub(c1...).AmountOf(i.A_DENOM).Uint64()).To(Equal(uint64(100))) + Expect(c2.Sub(c1...).AmountOf(i.B_DENOM).Uint64()).To(Equal(uint64(200))) + Expect(c2.Sub(c1...).AmountOf(i.C_DENOM).Uint64()).To(BeZero()) + + // assert total pool funds + Expect(s.App().FundersKeeper.GetTotalActiveFunding(s.Ctx(), fundingState.PoolId)[0].Amount.Uint64()).To(Equal(200*i.KYVE - 10_000)) + Expect(fundingState.ActiveFunderAddresses).To(HaveLen(2)) + }) + + It("Produce a valid bundle with multiple coins funded and 100% inflation splitting", func() { + // ARRANGE + params := pooltypes.DefaultParams() + params.ProtocolInflationShare = math.LegacyMustNewDecFromStr("1") + params.PoolInflationPayoutRate = math.LegacyMustNewDecFromStr("0.1") + s.App().PoolKeeper.SetParams(s.Ctx(), params) + + // mine some blocks + for i := 1; i < 100; i++ { + s.Commit() + } + + s.RunTxFundersSuccess(&funderstypes.MsgFundPool{ + Creator: i.ALICE, + PoolId: 0, + Amounts: sdk.NewCoins(i.ACoin(100*i.T_KYVE), i.BCoin(100*i.T_KYVE)), + AmountsPerBundle: sdk.NewCoins(i.ACoin(amountPerBundle), i.BCoin(2*amountPerBundle)), + }) + + s.RunTxFundersSuccess(&funderstypes.MsgFundPool{ + Creator: i.BOB, + PoolId: 0, + Amounts: sdk.NewCoins(i.ACoin(100*i.T_KYVE), i.BCoin(100*i.T_KYVE)), + AmountsPerBundle: sdk.NewCoins(i.ACoin(amountPerBundle), i.BCoin(2*amountPerBundle)), + }) + + s.RunTxBundlesSuccess(&bundletypes.MsgSubmitBundleProposal{ + Creator: i.VALADDRESS_0_A, + Staker: i.STAKER_0, + PoolId: 0, + StorageId: "y62A3tfbSNcNYDGoL-eXwzyV-Zc9Q0OVtDvR1biJmNI", + DataSize: 100, + DataHash: "test_hash", + FromIndex: 0, + BundleSize: 100, + FromKey: "0", + ToKey: "99", + BundleSummary: "test_value", + }) + + s.RunTxBundlesSuccess(&bundletypes.MsgVoteBundleProposal{ + Creator: i.VALADDRESS_1_A, + Staker: i.STAKER_1, + PoolId: 0, + StorageId: "y62A3tfbSNcNYDGoL-eXwzyV-Zc9Q0OVtDvR1biJmNI", + Vote: 1, + }) + + s.CommitAfterSeconds(60) + + b1 := s.GetBalanceFromPool(0) + c1 := s.GetCoinsFromCommunityPool() + + // ACT + s.RunTxBundlesSuccess(&bundletypes.MsgSubmitBundleProposal{ + Creator: i.VALADDRESS_1_A, + Staker: i.STAKER_1, + PoolId: 0, + StorageId: "P9edn0bjEfMU_lecFDIPLvGO2v2ltpFNUMWp5kgPddg", + DataSize: 100, + DataHash: "test_hash2", + FromIndex: 100, + BundleSize: 100, + FromKey: "100", + ToKey: "199", + BundleSummary: "test_value2", + }) + + // ASSERT + pool, _ := s.App().PoolKeeper.GetPool(s.Ctx(), 0) + + // assert if bundle go finalized + Expect(pool.TotalBundles).To(Equal(uint64(1))) + Expect(pool.CurrentKey).To(Equal("99")) + + // assert pool balance + b2 := s.GetBalanceFromPool(0) + Expect(b1).To(BeNumerically(">", b2)) + + // inflation payout is 24716741tkyve + payout := uint64(math.LegacyNewDec(int64(b1)).Mul(s.App().PoolKeeper.GetPoolInflationPayoutRate(s.Ctx())).TruncateInt64()) + Expect(b1 - b2).To(Equal(payout)) + + // assert bundle reward + uploader, _ := s.App().StakersKeeper.GetStaker(s.Ctx(), i.STAKER_0) + + // assert commission rewards (here we round down since the result of commission rewards gets truncated) + // for kyve coin (24_716_741 - (24_716_741 * 0.01) - _((100 * 0.5) / (3 * 1))_) * 0.1 + _((100 * 0.5) / (3 * 1))_ + // for acoin (10_000 - (10_000 * 0.01) - _((100 * 0.5) / (3 * 1))_) * 0.1 + _((100 * 0.5) / (3 * 1))_ + // for bcoin coins (20_000 - (20_000 * 0.01) - _((100 * 0.5) / (3 * 2))_) * 0.1 + _((100 * 0.5) / (3 * 2))_ + Expect(uploader.CommissionRewards.String()).To(Equal(sdk.NewCoins(i.KYVECoin(2_446_971), i.ACoin(1004), i.BCoin(1987)).String())) + // assert uploader self delegation rewards (here we round up since the result of delegation rewards is the remainder minus the truncated commission rewards) + // for kyve coin (24_716_741 - (24_716_741 * 0.01) - _((100 * 0.5) / (3 * 1))_) * (1 - 0.1) + // for acoin (10_000 - (10_000 * 0.01) - _((100 * 0.5) / (3 * 1))_) * (1 - 0.1) + // for bcoin (20_000 - (20_000 * 0.01) - _((100 * 0.5) / (3 * 2))_) * (1 - 0.1) + Expect(s.App().DelegationKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_0, i.STAKER_0).String()).To(Equal(sdk.NewCoins(i.KYVECoin(22_022_603), i.ACoin(8896), i.BCoin(17813)).String())) + + fundingState, _ := s.App().FundersKeeper.GetFundingState(s.Ctx(), 0) + + // assert treasury payout + c2 := s.GetCoinsFromCommunityPool() + Expect(c2.Sub(c1...).AmountOf(i.A_DENOM).Uint64()).To(Equal(uint64(100))) + Expect(c2.Sub(c1...).AmountOf(i.B_DENOM).Uint64()).To(Equal(uint64(200))) + Expect(c2.Sub(c1...).AmountOf(i.C_DENOM).Uint64()).To(BeZero()) + + // assert total pool funds + Expect(s.App().FundersKeeper.GetTotalActiveFunding(s.Ctx(), fundingState.PoolId)[0].Amount.Uint64()).To(Equal(200*i.KYVE - 10_000)) + Expect(fundingState.ActiveFunderAddresses).To(HaveLen(2)) }) It("Produce a valid bundle with no funders, 0% inflation splitting and 0 inflation-share-weight", func() { @@ -1443,7 +1741,7 @@ var _ = Describe("inflation splitting", Ordered, func() { // set team-share to zero to not interfere with inflation splitting teamTypes.TEAM_ALLOCATION = 0 - _ = s.App().BankKeeper.SendCoinsFromModuleToAccount(s.Ctx(), "team", types.MustAccAddressFromBech32(i.CHARLIE), s.GetCoinsFromModule("team")) + _ = s.App().BankKeeper.SendCoinsFromModuleToAccount(s.Ctx(), "team", sdk.MustAccAddressFromBech32(i.CHARLIE), s.GetCoinsFromModule("team")) pool, _ := s.App().PoolKeeper.GetPool(s.Ctx(), 0) pool.InflationShareWeight = math.LegacyMustNewDecFromStr("0.1") @@ -1596,7 +1894,7 @@ var _ = Describe("inflation splitting", Ordered, func() { // set team-share to zero to not interfere with inflation splitting teamTypes.TEAM_ALLOCATION = 0 - _ = s.App().BankKeeper.SendCoinsFromModuleToAccount(s.Ctx(), "team", types.MustAccAddressFromBech32(i.CHARLIE), s.GetCoinsFromModule("team")) + _ = s.App().BankKeeper.SendCoinsFromModuleToAccount(s.Ctx(), "team", sdk.MustAccAddressFromBech32(i.CHARLIE), s.GetCoinsFromModule("team")) pool, _ := s.App().PoolKeeper.GetPool(s.Ctx(), 0) pool.InflationShareWeight = math.LegacyMustNewDecFromStr("1") diff --git a/x/bundles/keeper/keeper_suite_valid_bundles_test.go b/x/bundles/keeper/keeper_suite_valid_bundles_test.go index 1cf3dc0c..edc63a3b 100644 --- a/x/bundles/keeper/keeper_suite_valid_bundles_test.go +++ b/x/bundles/keeper/keeper_suite_valid_bundles_test.go @@ -4,6 +4,7 @@ import ( "cosmossdk.io/math" fundersTypes "github.com/KYVENetwork/chain/x/funders/types" globalTypes "github.com/KYVENetwork/chain/x/global/types" + sdk "github.com/cosmos/cosmos-sdk/types" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" @@ -24,27 +25,30 @@ TEST CASES - valid bundles * Produce a valid bundle with multiple validators and foreign delegation although some voted abstain * Produce a valid bundle with multiple validators and foreign delegation although some voted invalid * Produce a valid bundle with multiple validators and no foreign delegations and another storage provider +* Produce a valid bundle with multiple validators, multiple coins and no foreign delegations +* Produce a valid bundle with multiple validators, multiple coins which are not enough for the storage reward and no foreign delegations +* Produce a valid bundle with multiple validator, multiple coins and no foreign delegations where one coin is removed from the whitelist */ var _ = Describe("valid bundles", Ordered, func() { var s *i.KeeperTestSuite - var initialBalanceStaker0, initialBalanceValaddress0, initialBalanceStaker1, initialBalanceValaddress1, initialBalanceStaker2, initialBalanceValaddress2 uint64 + var initialBalanceStaker0, initialBalanceValaddress0, initialBalanceStaker1, initialBalanceValaddress1, initialBalanceStaker2, initialBalanceValaddress2 sdk.Coins - amountPerBundle := uint64(10_000) + amountPerBundle := int64(10_000) BeforeEach(func() { // init new clean chain s = i.NewCleanChain() - initialBalanceStaker0 = s.GetBalanceFromAddress(i.STAKER_0) - initialBalanceValaddress0 = s.GetBalanceFromAddress(i.VALADDRESS_0_A) + initialBalanceStaker0 = s.GetCoinsFromAddress(i.STAKER_0) + initialBalanceValaddress0 = s.GetCoinsFromAddress(i.VALADDRESS_0_A) - initialBalanceStaker1 = s.GetBalanceFromAddress(i.STAKER_1) - initialBalanceValaddress1 = s.GetBalanceFromAddress(i.VALADDRESS_1_A) + initialBalanceStaker1 = s.GetCoinsFromAddress(i.STAKER_1) + initialBalanceValaddress1 = s.GetCoinsFromAddress(i.VALADDRESS_1_A) - initialBalanceStaker2 = s.GetBalanceFromAddress(i.STAKER_2) - initialBalanceValaddress2 = s.GetBalanceFromAddress(i.VALADDRESS_2_A) + initialBalanceStaker2 = s.GetCoinsFromAddress(i.STAKER_2) + initialBalanceValaddress2 = s.GetCoinsFromAddress(i.VALADDRESS_2_A) // create clean pool for every test case gov := s.App().GovKeeper.GetGovernanceAccount(s.Ctx()).GetAddress().String() @@ -61,7 +65,7 @@ var _ = Describe("valid bundles", Ordered, func() { MaxBundleSize: 100, Version: "0.0.0", Binaries: "{}", - StorageProviderId: 2, + StorageProviderId: 1, CompressionId: 1, } s.RunTxPoolSuccess(msg) @@ -72,13 +76,43 @@ var _ = Describe("valid bundles", Ordered, func() { Moniker: "Alice", }) - params := fundersTypes.DefaultParams() - params.CoinWhitelist[0].MinFundingAmountPerBundle = amountPerBundle - s.App().FundersKeeper.SetParams(s.Ctx(), params) + // set storage cost to 0.5 + bundleParams := s.App().BundlesKeeper.GetParams(s.Ctx()) + bundleParams.StorageCosts = append(bundleParams.StorageCosts, bundletypes.StorageCost{StorageProviderId: 1, Cost: math.LegacyMustNewDecFromStr("0.5")}) + s.App().BundlesKeeper.SetParams(s.Ctx(), bundleParams) + + // set funders params + s.App().FundersKeeper.SetParams(s.Ctx(), fundersTypes.NewParams([]*fundersTypes.WhitelistCoinEntry{ + { + CoinDenom: globalTypes.Denom, + MinFundingAmount: 10 * i.KYVE, + MinFundingAmountPerBundle: uint64(amountPerBundle), + CoinWeight: math.LegacyNewDec(1), + }, + { + CoinDenom: i.A_DENOM, + MinFundingAmount: 10 * i.KYVE, + MinFundingAmountPerBundle: uint64(amountPerBundle), + CoinWeight: math.LegacyNewDec(1), + }, + { + CoinDenom: i.B_DENOM, + MinFundingAmount: 10 * i.KYVE, + MinFundingAmountPerBundle: uint64(amountPerBundle), + CoinWeight: math.LegacyNewDec(2), + }, + { + CoinDenom: i.C_DENOM, + MinFundingAmount: 10 * i.KYVE, + MinFundingAmountPerBundle: uint64(amountPerBundle), + CoinWeight: math.LegacyNewDec(3), + }, + }, 0)) + s.RunTxPoolSuccess(&fundersTypes.MsgFundPool{ Creator: i.ALICE, - Amounts: i.KYVECoins(100 * i.T_KYVE), - AmountsPerBundle: i.KYVECoins(int64(amountPerBundle)), + Amounts: i.ACoins(100 * i.T_KYVE), + AmountsPerBundle: i.ACoins(amountPerBundle), }) s.RunTxStakersSuccess(&stakertypes.MsgCreateStaker{ @@ -109,11 +143,11 @@ var _ = Describe("valid bundles", Ordered, func() { PoolId: 0, }) - initialBalanceStaker0 = s.GetBalanceFromAddress(i.STAKER_0) - initialBalanceValaddress0 = s.GetBalanceFromAddress(i.VALADDRESS_0_A) + initialBalanceStaker0 = s.GetCoinsFromAddress(i.STAKER_0) + initialBalanceValaddress0 = s.GetCoinsFromAddress(i.VALADDRESS_0_A) - initialBalanceStaker1 = s.GetBalanceFromAddress(i.STAKER_1) - initialBalanceValaddress1 = s.GetBalanceFromAddress(i.VALADDRESS_1_A) + initialBalanceStaker1 = s.GetCoinsFromAddress(i.STAKER_1) + initialBalanceValaddress1 = s.GetCoinsFromAddress(i.VALADDRESS_1_A) s.CommitAfterSeconds(60) }) @@ -146,8 +180,10 @@ var _ = Describe("valid bundles", Ordered, func() { Vote: bundletypes.VOTE_TYPE_VALID, }) - initialBalanceStaker1 = s.GetBalanceFromAddress(i.STAKER_1) - initialBalanceValaddress1 = s.GetBalanceFromAddress(i.VALADDRESS_1_A) + initialBalanceStaker1 = s.GetCoinsFromAddress(i.STAKER_1) + initialBalanceValaddress1 = s.GetCoinsFromAddress(i.VALADDRESS_1_A) + + c1 := s.GetCoinsFromCommunityPool() s.CommitAfterSeconds(60) @@ -216,43 +252,42 @@ var _ = Describe("valid bundles", Ordered, func() { valaccountUploader, _ := s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_0) Expect(valaccountUploader.Points).To(BeZero()) - balanceUploaderValaddress := s.GetBalanceFromAddress(valaccountUploader.Valaddress) + balanceUploaderValaddress := s.GetCoinsFromAddress(valaccountUploader.Valaddress) Expect(balanceUploaderValaddress).To(Equal(initialBalanceValaddress0)) - balanceUploader := s.GetBalanceFromAddress(valaccountUploader.Staker) - uploader, _ := s.App().StakersKeeper.GetStaker(s.Ctx(), valaccountUploader.Staker) - // check voter status valaccountVoter, _ := s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_1) Expect(valaccountVoter.Points).To(BeZero()) - balanceVoterValaddress := s.GetBalanceFromAddress(valaccountVoter.Valaddress) + balanceVoterValaddress := s.GetCoinsFromAddress(valaccountVoter.Valaddress) Expect(balanceVoterValaddress).To(Equal(initialBalanceValaddress1)) - balanceVoter := s.GetBalanceFromAddress(valaccountVoter.Staker) + balanceVoter := s.GetCoinsFromAddress(valaccountVoter.Staker) Expect(balanceVoter).To(Equal(initialBalanceStaker1)) - // calculate uploader rewards - // calculate uploader rewards - networkFee := s.App().BundlesKeeper.GetNetworkFee(s.Ctx()) - treasuryReward := pool.InflationShareWeight.Mul(networkFee) - storageReward := s.App().BundlesKeeper.GetStorageCost(s.Ctx(), pool.CurrentStorageProviderId).MulInt64(100) - totalUploaderReward := pool.InflationShareWeight.Sub(treasuryReward).Sub(storageReward) - - uploaderPayoutReward := totalUploaderReward.Mul(uploader.Commission) - uploaderDelegationReward := totalUploaderReward.Sub(uploaderPayoutReward) + // check uploader rewards + uploader, _ := s.App().StakersKeeper.GetStaker(s.Ctx(), valaccountUploader.Staker) + balanceUploader := s.GetCoinsFromAddress(valaccountUploader.Staker) // assert payout transfer - Expect(balanceUploader).To(Equal(initialBalanceStaker0)) - // assert commission rewards - Expect(uploader.CommissionRewards.AmountOf(globalTypes.Denom).Uint64()).To(Equal(uint64(uploaderPayoutReward.Add(storageReward).TruncateInt64()))) + Expect(balanceUploader.String()).To(Equal(initialBalanceStaker0.String())) // assert uploader self delegation rewards - Expect(s.App().DelegationKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_0, i.STAKER_0).AmountOf(globalTypes.Denom).Uint64()).To(Equal(uint64(uploaderDelegationReward.TruncateInt64()))) + // (total_bundle_payout - treasury_reward - storage_cost) * (1 - commission) + // (10_000 - (10_000 * 0.01) - (100 * 0.5)) * (1 - 0.1) + Expect(s.App().DelegationKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_0, i.STAKER_0).String()).To(Equal(i.ACoins(8865).String())) + // assert commission rewards + // (total_bundle_payout - treasury_reward - storage_cost) * commission + storage_cost + // (10_000 - (10_000 * 0.01) - (100 * 0.5)) * 0.1 + (100 * 0.5) + Expect(uploader.CommissionRewards.String()).To(Equal(i.ACoins(1035).String())) fundingState, _ := s.App().FundersKeeper.GetFundingState(s.Ctx(), 0) + // assert treasury payout + c2 := s.GetCoinsFromCommunityPool() + Expect(c2.Sub(c1...).AmountOf(i.A_DENOM).Uint64()).To(Equal(uint64(100))) + // assert total pool funds - Expect(s.App().FundersKeeper.GetTotalActiveFunding(s.Ctx(), fundingState.PoolId)[0].Amount.Uint64()).To(Equal(100*i.KYVE - 1*amountPerBundle)) + Expect(s.App().FundersKeeper.GetTotalActiveFunding(s.Ctx(), fundingState.PoolId).String()).To(Equal(i.ACoins(100*i.T_KYVE - amountPerBundle).String())) Expect(fundingState.ActiveFunderAddresses).To(HaveLen(1)) }) @@ -292,8 +327,10 @@ var _ = Describe("valid bundles", Ordered, func() { Vote: bundletypes.VOTE_TYPE_VALID, }) - initialBalanceStaker1 = s.GetBalanceFromAddress(i.STAKER_1) - initialBalanceValaddress1 = s.GetBalanceFromAddress(i.VALADDRESS_1_A) + initialBalanceStaker1 = s.GetCoinsFromAddress(i.STAKER_1) + initialBalanceValaddress1 = s.GetCoinsFromAddress(i.VALADDRESS_1_A) + + c1 := s.GetCoinsFromCommunityPool() s.CommitAfterSeconds(60) @@ -362,58 +399,46 @@ var _ = Describe("valid bundles", Ordered, func() { valaccountUploader, _ := s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_0) Expect(valaccountUploader.Points).To(BeZero()) - balanceUploaderValaddress := s.GetBalanceFromAddress(valaccountUploader.Valaddress) + balanceUploaderValaddress := s.GetCoinsFromAddress(valaccountUploader.Valaddress) Expect(balanceUploaderValaddress).To(Equal(initialBalanceValaddress0)) - balanceUploader := s.GetBalanceFromAddress(valaccountUploader.Staker) - uploader, _ := s.App().StakersKeeper.GetStaker(s.Ctx(), valaccountUploader.Staker) - // check voter status valaccountVoter, _ := s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_1) Expect(valaccountVoter.Points).To(BeZero()) - balanceVoterValaddress := s.GetBalanceFromAddress(valaccountVoter.Valaddress) + balanceVoterValaddress := s.GetCoinsFromAddress(valaccountVoter.Valaddress) Expect(balanceVoterValaddress).To(Equal(initialBalanceValaddress1)) - balanceVoter := s.GetBalanceFromAddress(valaccountVoter.Staker) + balanceVoter := s.GetCoinsFromAddress(valaccountVoter.Staker) Expect(balanceVoter).To(Equal(initialBalanceStaker1)) - // calculate uploader rewards - networkFee := s.App().BundlesKeeper.GetNetworkFee(s.Ctx()) - treasuryReward := pool.InflationShareWeight.Mul(networkFee) - storageReward := s.App().BundlesKeeper.GetStorageCost(s.Ctx(), pool.CurrentStorageProviderId).MulInt64(100) - totalUploaderReward := pool.InflationShareWeight.Sub(treasuryReward).Sub(storageReward) - - uploaderPayoutReward := totalUploaderReward.Mul(uploader.Commission) - totalDelegationReward := totalUploaderReward.Sub(uploaderPayoutReward) - - // divide with 4 because uploader only has 25% of total delegation - uploaderDelegationReward := totalDelegationReward.Quo(math.LegacyNewDec(4)) - delegatorDelegationReward := totalDelegationReward.Quo(math.LegacyNewDec(4)).Mul(math.LegacyNewDec(3)) + // check uploader rewards + uploader, _ := s.App().StakersKeeper.GetStaker(s.Ctx(), valaccountUploader.Staker) + balanceUploader := s.GetCoinsFromAddress(valaccountUploader.Staker) // assert payout transfer - Expect(balanceUploader).To(Equal(initialBalanceStaker0)) + Expect(balanceUploader.String()).To(Equal(initialBalanceStaker0.String())) // assert commission rewards - Expect(uploader.CommissionRewards.AmountOf(globalTypes.Denom).Uint64()).To(Equal(uint64(uploaderPayoutReward.Add(storageReward).TruncateInt64()))) + // (10_000 - (10_000 * 0.01) - (100 * 0.5)) * 0.1 + (100 * 0.5) + Expect(uploader.CommissionRewards.String()).To(Equal(i.ACoins(1035).String())) // assert uploader self delegation rewards - Expect(s.App().DelegationKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_0, i.STAKER_0).AmountOf(globalTypes.Denom).Uint64()).To(Equal(uint64(uploaderDelegationReward.TruncateInt64()))) + // (10_000 - (10_000 * 0.01) - (100 * 0.5)) * (1 - 0.1) * (1/4) + Expect(s.App().DelegationKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_0, i.STAKER_0).String()).To(Equal(i.ACoins(2216).String())) // assert delegator delegation rewards - Expect(s.App().DelegationKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_0, i.ALICE).AmountOf(globalTypes.Denom).Uint64()).To(Equal(uint64(delegatorDelegationReward.TruncateInt64()))) + // (10_000 - (10_000 * 0.01) - (100 * 0.5)) * (1 - 0.1) * (3/4) + Expect(s.App().DelegationKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_0, i.ALICE).String()).To(Equal(i.ACoins(6648).String())) // check voter rewards Expect(s.App().DelegationKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_1, i.BOB)).To(BeEmpty()) - // assert payout transfer - Expect(balanceUploader).To(Equal(initialBalanceStaker0)) - // assert commission rewards - Expect(uploader.CommissionRewards.AmountOf(globalTypes.Denom).Uint64()).To(Equal(uint64(uploaderPayoutReward.Add(storageReward).TruncateInt64()))) - // assert uploader self delegation rewards - Expect(s.App().DelegationKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_0, i.STAKER_0).AmountOf(globalTypes.Denom).Uint64()).To(Equal(uint64(uploaderDelegationReward.TruncateInt64()))) - fundingState, _ := s.App().FundersKeeper.GetFundingState(s.Ctx(), 0) + // assert treasury payout + c2 := s.GetCoinsFromCommunityPool() + Expect(c2.Sub(c1...).AmountOf(i.A_DENOM).Uint64()).To(Equal(uint64(100))) + // assert total pool funds - Expect(s.App().FundersKeeper.GetTotalActiveFunding(s.Ctx(), fundingState.PoolId)[0].Amount.Uint64()).To(Equal(100*i.KYVE - 1*amountPerBundle)) + Expect(s.App().FundersKeeper.GetTotalActiveFunding(s.Ctx(), fundingState.PoolId).String()).To(Equal(i.ACoins(100*i.T_KYVE - amountPerBundle).String())) Expect(fundingState.ActiveFunderAddresses).To(HaveLen(1)) }) @@ -470,8 +495,10 @@ var _ = Describe("valid bundles", Ordered, func() { Vote: bundletypes.VOTE_TYPE_VALID, }) - initialBalanceStaker1 = s.GetBalanceFromAddress(i.STAKER_1) - initialBalanceValaddress1 = s.GetBalanceFromAddress(i.VALADDRESS_1_A) + initialBalanceStaker1 = s.GetCoinsFromAddress(i.STAKER_1) + initialBalanceValaddress1 = s.GetCoinsFromAddress(i.VALADDRESS_1_A) + + c1 := s.GetCoinsFromCommunityPool() s.CommitAfterSeconds(60) @@ -540,51 +567,46 @@ var _ = Describe("valid bundles", Ordered, func() { valaccountUploader, _ := s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_0) Expect(valaccountUploader.Points).To(BeZero()) - balanceUploaderValaddress := s.GetBalanceFromAddress(valaccountUploader.Valaddress) + balanceUploaderValaddress := s.GetCoinsFromAddress(valaccountUploader.Valaddress) Expect(balanceUploaderValaddress).To(Equal(initialBalanceValaddress0)) - balanceUploader := s.GetBalanceFromAddress(valaccountUploader.Staker) - uploader, _ := s.App().StakersKeeper.GetStaker(s.Ctx(), valaccountUploader.Staker) - // check voter status valaccountVoter, _ := s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_2) Expect(valaccountVoter.Points).To(Equal(uint64(1))) - balanceVoterValaddress := s.GetBalanceFromAddress(valaccountVoter.Valaddress) + balanceVoterValaddress := s.GetCoinsFromAddress(valaccountVoter.Valaddress) Expect(balanceVoterValaddress).To(Equal(initialBalanceValaddress1)) - balanceVoter := s.GetBalanceFromAddress(valaccountVoter.Staker) + balanceVoter := s.GetCoinsFromAddress(valaccountVoter.Staker) Expect(balanceVoter).To(Equal(initialBalanceStaker1)) - // calculate uploader rewards - networkFee := s.App().BundlesKeeper.GetNetworkFee(s.Ctx()) - treasuryReward := pool.InflationShareWeight.Mul(networkFee) - storageReward := s.App().BundlesKeeper.GetStorageCost(s.Ctx(), pool.CurrentStorageProviderId).MulInt64(100) - totalUploaderReward := pool.InflationShareWeight.Sub(treasuryReward).Sub(storageReward) - - uploaderPayoutReward := totalUploaderReward.Mul(uploader.Commission) - totalDelegationReward := totalUploaderReward.Sub(uploaderPayoutReward) - - // divide with 4 because uploader only has 25% of total delegation - uploaderDelegationReward := totalDelegationReward.Quo(math.LegacyNewDec(4)) - delegatorDelegationReward := totalDelegationReward.Quo(math.LegacyNewDec(4)).Mul(math.LegacyNewDec(3)) + // check uploader rewards + uploader, _ := s.App().StakersKeeper.GetStaker(s.Ctx(), valaccountUploader.Staker) + balanceUploader := s.GetCoinsFromAddress(valaccountUploader.Staker) // assert payout transfer - Expect(balanceUploader).To(Equal(initialBalanceStaker0)) + Expect(balanceUploader.String()).To(Equal(initialBalanceStaker0.String())) // assert commission rewards - Expect(uploader.CommissionRewards.AmountOf(globalTypes.Denom).Uint64()).To(Equal(uint64(uploaderPayoutReward.Add(storageReward).TruncateInt64()))) + // (10_000 - (10_000 * 0.01) - (100 * 0.5)) * 0.1 + (100 * 0.5) + Expect(uploader.CommissionRewards.String()).To(Equal(i.ACoins(1035).String())) // assert uploader self delegation rewards - Expect(s.App().DelegationKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_0, i.STAKER_0).AmountOf(globalTypes.Denom).Uint64()).To(Equal(uint64(uploaderDelegationReward.TruncateInt64()))) + // (10_000 - (10_000 * 0.01) - (100 * 0.5)) * (1 - 0.1) * (1/4) + Expect(s.App().DelegationKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_0, i.STAKER_0).String()).To(Equal(i.ACoins(2216).String())) // assert delegator delegation rewards - Expect(s.App().DelegationKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_0, i.ALICE).AmountOf(globalTypes.Denom).Uint64()).To(Equal(uint64(delegatorDelegationReward.TruncateInt64()))) + // (10_000 - (10_000 * 0.01) - (100 * 0.5)) * (1 - 0.1) * (3/4) + Expect(s.App().DelegationKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_0, i.ALICE).String()).To(Equal(i.ACoins(6648).String())) // check voter rewards Expect(s.App().DelegationKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_2, i.CHARLIE)).To(BeEmpty()) fundingState, _ := s.App().FundersKeeper.GetFundingState(s.Ctx(), 0) + // assert treasury payout + c2 := s.GetCoinsFromCommunityPool() + Expect(c2.Sub(c1...).AmountOf(i.A_DENOM).Uint64()).To(Equal(uint64(100))) + // assert total pool funds - Expect(s.App().FundersKeeper.GetTotalActiveFunding(s.Ctx(), fundingState.PoolId)[0].Amount.Uint64()).To(Equal(100*i.KYVE - 1*amountPerBundle)) + Expect(s.App().FundersKeeper.GetTotalActiveFunding(s.Ctx(), fundingState.PoolId).String()).To(Equal(i.ACoins(100*i.T_KYVE - amountPerBundle).String())) Expect(fundingState.ActiveFunderAddresses).To(HaveLen(1)) }) @@ -649,8 +671,10 @@ var _ = Describe("valid bundles", Ordered, func() { Vote: bundletypes.VOTE_TYPE_ABSTAIN, }) - initialBalanceStaker1 = s.GetBalanceFromAddress(i.STAKER_1) - initialBalanceValaddress1 = s.GetBalanceFromAddress(i.VALADDRESS_1_A) + initialBalanceStaker1 = s.GetCoinsFromAddress(i.STAKER_1) + initialBalanceValaddress1 = s.GetCoinsFromAddress(i.VALADDRESS_1_A) + + c1 := s.GetCoinsFromCommunityPool() s.CommitAfterSeconds(60) @@ -719,51 +743,46 @@ var _ = Describe("valid bundles", Ordered, func() { valaccountUploader, _ := s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_0) Expect(valaccountUploader.Points).To(BeZero()) - balanceUploaderValaddress := s.GetBalanceFromAddress(valaccountUploader.Valaddress) + balanceUploaderValaddress := s.GetCoinsFromAddress(valaccountUploader.Valaddress) Expect(balanceUploaderValaddress).To(Equal(initialBalanceValaddress0)) - balanceUploader := s.GetBalanceFromAddress(valaccountUploader.Staker) - uploader, _ := s.App().StakersKeeper.GetStaker(s.Ctx(), valaccountUploader.Staker) - // check voter status valaccountVoter, _ := s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_1) Expect(valaccountVoter.Points).To(BeZero()) - balanceVoterValaddress := s.GetBalanceFromAddress(valaccountVoter.Valaddress) + balanceVoterValaddress := s.GetCoinsFromAddress(valaccountVoter.Valaddress) Expect(balanceVoterValaddress).To(Equal(initialBalanceValaddress1)) - balanceVoter := s.GetBalanceFromAddress(valaccountVoter.Staker) + balanceVoter := s.GetCoinsFromAddress(valaccountVoter.Staker) Expect(balanceVoter).To(Equal(initialBalanceStaker1)) - // calculate uploader rewards - networkFee := s.App().BundlesKeeper.GetNetworkFee(s.Ctx()) - treasuryReward := pool.InflationShareWeight.Mul(networkFee) - storageReward := s.App().BundlesKeeper.GetStorageCost(s.Ctx(), pool.CurrentStorageProviderId).MulInt64(100) - totalUploaderReward := pool.InflationShareWeight.Sub(treasuryReward).Sub(storageReward) - - uploaderPayoutReward := totalUploaderReward.Mul(uploader.Commission) - totalDelegationReward := totalUploaderReward.Sub(uploaderPayoutReward) - - // divide with 4 because uploader only has 25% of total delegation - uploaderDelegationReward := totalDelegationReward.Quo(math.LegacyNewDec(4)) - delegatorDelegationReward := totalDelegationReward.Quo(math.LegacyNewDec(4)).Mul(math.LegacyNewDec(3)) + // check uploader rewards + uploader, _ := s.App().StakersKeeper.GetStaker(s.Ctx(), valaccountUploader.Staker) + balanceUploader := s.GetCoinsFromAddress(valaccountUploader.Staker) // assert payout transfer - Expect(balanceUploader).To(Equal(initialBalanceStaker0)) + Expect(balanceUploader.String()).To(Equal(initialBalanceStaker0.String())) // assert commission rewards - Expect(uploader.CommissionRewards.AmountOf(globalTypes.Denom).Uint64()).To(Equal(uint64(uploaderPayoutReward.Add(storageReward).TruncateInt64()))) + // (10_000 - (10_000 * 0.01) - (100 * 0.5)) * 0.1 + (100 * 0.5) + Expect(uploader.CommissionRewards.String()).To(Equal(i.ACoins(1035).String())) // assert uploader self delegation rewards - Expect(s.App().DelegationKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_0, i.STAKER_0).AmountOf(globalTypes.Denom).Uint64()).To(Equal(uint64(uploaderDelegationReward.TruncateInt64()))) + // (10_000 - (10_000 * 0.01) - (100 * 0.5)) * (1 - 0.1) * (1/4) + Expect(s.App().DelegationKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_0, i.STAKER_0).String()).To(Equal(i.ACoins(2216).String())) // assert delegator delegation rewards - Expect(s.App().DelegationKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_0, i.ALICE).AmountOf(globalTypes.Denom).Uint64()).To(Equal(uint64(delegatorDelegationReward.TruncateInt64()))) + // (10_000 - (10_000 * 0.01) - (100 * 0.5)) * (1 - 0.1) * (3/4) + Expect(s.App().DelegationKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_0, i.ALICE).String()).To(Equal(i.ACoins(6648).String())) // check voter rewards Expect(s.App().DelegationKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_2, i.CHARLIE)).To(BeEmpty()) fundingState, _ := s.App().FundersKeeper.GetFundingState(s.Ctx(), 0) + // assert treasury payout + c2 := s.GetCoinsFromCommunityPool() + Expect(c2.Sub(c1...).AmountOf(i.A_DENOM).Uint64()).To(Equal(uint64(100))) + // assert total pool funds - Expect(s.App().FundersKeeper.GetTotalActiveFunding(s.Ctx(), fundingState.PoolId)[0].Amount.Uint64()).To(Equal(100*i.KYVE - 1*amountPerBundle)) + Expect(s.App().FundersKeeper.GetTotalActiveFunding(s.Ctx(), fundingState.PoolId).String()).To(Equal(i.ACoins(100*i.T_KYVE - amountPerBundle).String())) Expect(fundingState.ActiveFunderAddresses).To(HaveLen(1)) }) @@ -828,8 +847,10 @@ var _ = Describe("valid bundles", Ordered, func() { Vote: bundletypes.VOTE_TYPE_INVALID, }) - initialBalanceStaker2 = s.GetBalanceFromAddress(i.STAKER_2) - initialBalanceValaddress2 = s.GetBalanceFromAddress(i.VALADDRESS_2_A) + initialBalanceStaker2 = s.GetCoinsFromAddress(i.STAKER_2) + initialBalanceValaddress2 = s.GetCoinsFromAddress(i.VALADDRESS_2_A) + + c1 := s.GetCoinsFromCommunityPool() s.CommitAfterSeconds(60) @@ -898,12 +919,9 @@ var _ = Describe("valid bundles", Ordered, func() { valaccountUploader, _ := s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_0) Expect(valaccountUploader.Points).To(BeZero()) - balanceUploaderValaddress := s.GetBalanceFromAddress(valaccountUploader.Valaddress) + balanceUploaderValaddress := s.GetCoinsFromAddress(valaccountUploader.Valaddress) Expect(balanceUploaderValaddress).To(Equal(initialBalanceValaddress0)) - balanceUploader := s.GetBalanceFromAddress(valaccountUploader.Staker) - uploader, _ := s.App().StakersKeeper.GetStaker(s.Ctx(), valaccountUploader.Staker) - // calculate voter slashes fraction := s.App().DelegationKeeper.GetVoteSlash(s.Ctx()) slashAmountVoter := uint64(math.LegacyNewDec(int64(100 * i.KYVE)).Mul(fraction).TruncateInt64()) @@ -918,50 +936,48 @@ var _ = Describe("valid bundles", Ordered, func() { _, valaccountVoterFound := s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_2) Expect(valaccountVoterFound).To(BeFalse()) - balanceVoterValaddress := s.GetBalanceFromAddress(i.VALADDRESS_2_A) + balanceVoterValaddress := s.GetCoinsFromAddress(i.VALADDRESS_2_A) Expect(balanceVoterValaddress).To(Equal(initialBalanceValaddress2)) - balanceVoter := s.GetBalanceFromAddress(i.STAKER_2) + balanceVoter := s.GetCoinsFromAddress(i.STAKER_2) Expect(balanceVoter).To(Equal(initialBalanceStaker2)) - // calculate uploader rewards - networkFee := s.App().BundlesKeeper.GetNetworkFee(s.Ctx()) - treasuryReward := pool.InflationShareWeight.Mul(networkFee) - storageReward := s.App().BundlesKeeper.GetStorageCost(s.Ctx(), pool.CurrentStorageProviderId).MulInt64(100) - totalUploaderReward := pool.InflationShareWeight.Sub(treasuryReward).Sub(storageReward) - - uploaderPayoutReward := totalUploaderReward.Mul(uploader.Commission) - totalDelegationReward := totalUploaderReward.Sub(uploaderPayoutReward) - - // divide with 4 because uploader only has 25% of total delegation - uploaderDelegationReward := totalDelegationReward.Quo(math.LegacyNewDec(4)) - delegatorDelegationReward := totalDelegationReward.Quo(math.LegacyNewDec(4)).Mul(math.LegacyNewDec(3)) + // check uploader rewards + uploader, _ := s.App().StakersKeeper.GetStaker(s.Ctx(), valaccountUploader.Staker) + balanceUploader := s.GetCoinsFromAddress(valaccountUploader.Staker) // assert payout transfer - Expect(balanceUploader).To(Equal(initialBalanceStaker0)) + Expect(balanceUploader.String()).To(Equal(initialBalanceStaker0.String())) // assert commission rewards - Expect(uploader.CommissionRewards.AmountOf(globalTypes.Denom).Uint64()).To(Equal(uint64(uploaderPayoutReward.Add(storageReward).TruncateInt64()))) + // (10_000 - (10_000 * 0.01) - (100 * 0.5)) * 0.1 + (100 * 0.5) + Expect(uploader.CommissionRewards.String()).To(Equal(i.ACoins(1035).String())) // assert uploader self delegation rewards - Expect(s.App().DelegationKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_0, i.STAKER_0).AmountOf(globalTypes.Denom).Uint64()).To(Equal(uint64(uploaderDelegationReward.TruncateInt64()))) + // (10_000 - (10_000 * 0.01) - (100 * 0.5)) * (1 - 0.1) * (1/4) + Expect(s.App().DelegationKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_0, i.STAKER_0).String()).To(Equal(i.ACoins(2216).String())) // assert delegator delegation rewards - Expect(s.App().DelegationKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_0, i.ALICE).AmountOf(globalTypes.Denom).Uint64()).To(Equal(uint64(delegatorDelegationReward.TruncateInt64()))) + // (10_000 - (10_000 * 0.01) - (100 * 0.5)) * (1 - 0.1) * (3/4) + Expect(s.App().DelegationKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_0, i.ALICE).String()).To(Equal(i.ACoins(6648).String())) // check voter rewards Expect(s.App().DelegationKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_2, i.CHARLIE)).To(BeEmpty()) fundingState, _ := s.App().FundersKeeper.GetFundingState(s.Ctx(), 0) + // assert treasury payout + c2 := s.GetCoinsFromCommunityPool() + Expect(c2.Sub(c1...).AmountOf(i.A_DENOM).Uint64()).To(Equal(uint64(100))) + // assert total pool funds - Expect(s.App().FundersKeeper.GetTotalActiveFunding(s.Ctx(), fundingState.PoolId)[0].Amount.Uint64()).To(Equal(100*i.KYVE - 1*amountPerBundle)) + Expect(s.App().FundersKeeper.GetTotalActiveFunding(s.Ctx(), fundingState.PoolId).String()).To(Equal(i.ACoins(100*i.T_KYVE - amountPerBundle).String())) Expect(fundingState.ActiveFunderAddresses).To(HaveLen(1)) }) It("Produce a valid bundle with multiple validators and no foreign delegations and another storage provider", func() { // ARRANGE - storageProviderId := uint32(1) + storageProviderId := uint32(2) params := s.App().BundlesKeeper.GetParams(s.Ctx()) - params.StorageCosts = append(params.StorageCosts, bundletypes.StorageCost{StorageProviderId: 1, Cost: math.LegacyMustNewDecFromStr("0.9")}) + params.StorageCosts = append(params.StorageCosts, bundletypes.StorageCost{StorageProviderId: 2, Cost: math.LegacyMustNewDecFromStr("0.9")}) s.App().BundlesKeeper.SetParams(s.Ctx(), params) pool, _ := s.App().PoolKeeper.GetPool(s.Ctx(), 0) @@ -990,8 +1006,10 @@ var _ = Describe("valid bundles", Ordered, func() { Vote: bundletypes.VOTE_TYPE_VALID, }) - initialBalanceStaker1 = s.GetBalanceFromAddress(i.STAKER_1) - initialBalanceValaddress1 = s.GetBalanceFromAddress(i.VALADDRESS_1_A) + initialBalanceStaker1 = s.GetCoinsFromAddress(i.STAKER_1) + initialBalanceValaddress1 = s.GetCoinsFromAddress(i.VALADDRESS_1_A) + + c1 := s.GetCoinsFromCommunityPool() s.CommitAfterSeconds(60) @@ -1060,45 +1078,516 @@ var _ = Describe("valid bundles", Ordered, func() { valaccountUploader, _ := s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_0) Expect(valaccountUploader.Points).To(BeZero()) - balanceUploaderValaddress := s.GetBalanceFromAddress(valaccountUploader.Valaddress) + balanceUploaderValaddress := s.GetCoinsFromAddress(valaccountUploader.Valaddress) Expect(balanceUploaderValaddress).To(Equal(initialBalanceValaddress0)) - balanceUploader := s.GetBalanceFromAddress(valaccountUploader.Staker) + // check voter status + valaccountVoter, _ := s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_1) + Expect(valaccountVoter.Points).To(BeZero()) + + balanceVoterValaddress := s.GetCoinsFromAddress(valaccountVoter.Valaddress) + Expect(balanceVoterValaddress).To(Equal(initialBalanceValaddress1)) + + balanceVoter := s.GetCoinsFromAddress(valaccountVoter.Staker) + Expect(balanceVoter).To(Equal(initialBalanceStaker1)) + + // check uploader rewards uploader, _ := s.App().StakersKeeper.GetStaker(s.Ctx(), valaccountUploader.Staker) + balanceUploader := s.GetCoinsFromAddress(valaccountUploader.Staker) + + // assert payout transfer + Expect(balanceUploader.String()).To(Equal(initialBalanceStaker0.String())) + // assert uploader self delegation rewards + // (10_000 - (10_000 * 0.01) - (100 * 0.9)) * (1 - 0.1) + Expect(s.App().DelegationKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_0, i.STAKER_0).String()).To(Equal(i.ACoins(8829).String())) + // assert commission rewards + // (10_000 - (10_000 * 0.01) - (100 * 0.9)) * 0.1 + (100 * 0.9) + Expect(uploader.CommissionRewards.String()).To(Equal(i.ACoins(1071).String())) + + fundingState, _ := s.App().FundersKeeper.GetFundingState(s.Ctx(), 0) + + // assert treasury payout + c2 := s.GetCoinsFromCommunityPool() + Expect(c2.Sub(c1...).AmountOf(i.A_DENOM).Uint64()).To(Equal(uint64(100))) + + // assert total pool funds + Expect(s.App().FundersKeeper.GetTotalActiveFunding(s.Ctx(), fundingState.PoolId).String()).To(Equal(i.ACoins(100*i.T_KYVE - amountPerBundle).String())) + Expect(fundingState.ActiveFunderAddresses).To(HaveLen(1)) + }) + + It("Produce a valid bundle with multiple validators, multiple coins which are not enough for the storage reward and no foreign delegations", func() { + // ARRANGE + // fund additionally to the already funded 100acoins + s.RunTxPoolSuccess(&fundersTypes.MsgFundPool{ + Creator: i.ALICE, + Amounts: sdk.NewCoins(i.BCoin(200*i.T_KYVE), i.CCoin(300*i.T_KYVE)), + AmountsPerBundle: sdk.NewCoins(i.BCoin(2*amountPerBundle), i.CCoin(3*amountPerBundle)), + }) + + s.RunTxBundlesSuccess(&bundletypes.MsgSubmitBundleProposal{ + Creator: i.VALADDRESS_0_A, + Staker: i.STAKER_0, + PoolId: 0, + StorageId: "y62A3tfbSNcNYDGoL-eXwzyV-Zc9Q0OVtDvR1biJmNI", + DataSize: 100, + DataHash: "test_hash", + FromIndex: 0, + BundleSize: 100, + FromKey: "0", + ToKey: "99", + BundleSummary: "test_value", + }) + + s.RunTxBundlesSuccess(&bundletypes.MsgVoteBundleProposal{ + Creator: i.VALADDRESS_1_A, + Staker: i.STAKER_1, + PoolId: 0, + StorageId: "y62A3tfbSNcNYDGoL-eXwzyV-Zc9Q0OVtDvR1biJmNI", + Vote: bundletypes.VOTE_TYPE_VALID, + }) + + initialBalanceStaker1 = s.GetCoinsFromAddress(i.STAKER_1) + initialBalanceValaddress1 = s.GetCoinsFromAddress(i.VALADDRESS_1_A) + + c1 := s.GetCoinsFromCommunityPool() + + s.CommitAfterSeconds(60) + + // ACT + s.RunTxBundlesSuccess(&bundletypes.MsgSubmitBundleProposal{ + Creator: i.VALADDRESS_1_A, + Staker: i.STAKER_1, + PoolId: 0, + StorageId: "P9edn0bjEfMU_lecFDIPLvGO2v2ltpFNUMWp5kgPddg", + DataSize: 100, + DataHash: "test_hash2", + FromIndex: 100, + BundleSize: 100, + FromKey: "100", + ToKey: "199", + BundleSummary: "test_value2", + }) + + // ASSERT + // check if bundle got finalized on pool + pool, poolFound := s.App().PoolKeeper.GetPool(s.Ctx(), 0) + Expect(poolFound).To(BeTrue()) + + Expect(pool.CurrentKey).To(Equal("99")) + Expect(pool.CurrentSummary).To(Equal("test_value")) + Expect(pool.CurrentIndex).To(Equal(uint64(100))) + Expect(pool.TotalBundles).To(Equal(uint64(1))) + + // check if finalized bundle got saved + finalizedBundle, finalizedBundleFound := s.App().BundlesKeeper.GetFinalizedBundle(s.Ctx(), 0, 0) + Expect(finalizedBundleFound).To(BeTrue()) + + Expect(finalizedBundle.PoolId).To(Equal(uint64(0))) + Expect(finalizedBundle.StorageId).To(Equal("y62A3tfbSNcNYDGoL-eXwzyV-Zc9Q0OVtDvR1biJmNI")) + Expect(finalizedBundle.Uploader).To(Equal(i.STAKER_0)) + Expect(finalizedBundle.FromIndex).To(Equal(uint64(0))) + Expect(finalizedBundle.ToIndex).To(Equal(uint64(100))) + Expect(finalizedBundle.FromKey).To(Equal("0")) + Expect(finalizedBundle.ToKey).To(Equal("99")) + Expect(finalizedBundle.BundleSummary).To(Equal("test_value")) + Expect(finalizedBundle.DataHash).To(Equal("test_hash")) + Expect(finalizedBundle.FinalizedAt).NotTo(BeZero()) + Expect(finalizedBundle.StakeSecurity.ValidVotePower).To(Equal(200 * i.KYVE)) + Expect(finalizedBundle.StakeSecurity.TotalVotePower).To(Equal(200 * i.KYVE)) + + // check if next bundle proposal got registered + bundleProposal, bundleProposalFound := s.App().BundlesKeeper.GetBundleProposal(s.Ctx(), 0) + Expect(bundleProposalFound).To(BeTrue()) + + Expect(bundleProposal.PoolId).To(Equal(uint64(0))) + Expect(bundleProposal.StorageId).To(Equal("P9edn0bjEfMU_lecFDIPLvGO2v2ltpFNUMWp5kgPddg")) + Expect(bundleProposal.Uploader).To(Equal(i.STAKER_1)) + Expect(bundleProposal.NextUploader).NotTo(BeEmpty()) + Expect(bundleProposal.DataSize).To(Equal(uint64(100))) + Expect(bundleProposal.DataHash).To(Equal("test_hash2")) + Expect(bundleProposal.BundleSize).To(Equal(uint64(100))) + Expect(bundleProposal.FromKey).To(Equal("100")) + Expect(bundleProposal.ToKey).To(Equal("199")) + Expect(bundleProposal.BundleSummary).To(Equal("test_value2")) + Expect(bundleProposal.UpdatedAt).NotTo(BeZero()) + Expect(bundleProposal.VotersValid).To(ContainElement(i.STAKER_1)) + Expect(bundleProposal.VotersInvalid).To(BeEmpty()) + Expect(bundleProposal.VotersAbstain).To(BeEmpty()) + + // check uploader status + valaccountUploader, _ := s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_0) + Expect(valaccountUploader.Points).To(BeZero()) + + balanceUploaderValaddress := s.GetCoinsFromAddress(valaccountUploader.Valaddress) + Expect(balanceUploaderValaddress).To(Equal(initialBalanceValaddress0)) // check voter status valaccountVoter, _ := s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_1) Expect(valaccountVoter.Points).To(BeZero()) - balanceVoterValaddress := s.GetBalanceFromAddress(valaccountVoter.Valaddress) + balanceVoterValaddress := s.GetCoinsFromAddress(valaccountVoter.Valaddress) Expect(balanceVoterValaddress).To(Equal(initialBalanceValaddress1)) - balanceVoter := s.GetBalanceFromAddress(valaccountVoter.Staker) + balanceVoter := s.GetCoinsFromAddress(valaccountVoter.Staker) Expect(balanceVoter).To(Equal(initialBalanceStaker1)) - // calculate uploader rewards - networkFee := s.App().BundlesKeeper.GetNetworkFee(s.Ctx()) - whitelist := s.App().FundersKeeper.GetCoinWhitelistMap(s.Ctx()) - treasuryReward := pool.InflationShareWeight.Mul(networkFee) - storageReward := s.App().BundlesKeeper.GetStorageCost(s.Ctx(), storageProviderId).Quo(whitelist[globalTypes.Denom].CoinWeight).MulInt64(100) - totalUploaderReward := pool.InflationShareWeight.Sub(treasuryReward).Sub(storageReward) + // check uploader rewards + uploader, _ := s.App().StakersKeeper.GetStaker(s.Ctx(), valaccountUploader.Staker) + balanceUploader := s.GetCoinsFromAddress(valaccountUploader.Staker) + + // assert payout transfer + Expect(balanceUploader.String()).To(Equal(initialBalanceStaker0.String())) + // assert commission rewards (here we round down since the result of commission rewards gets truncated) + // (coin_amount_per_bundle - (coin_amount_per_bundle * 0.01) - _((100 * 0.5) / (3 * coin_weight))_) * 0.1 + _((100 * 0.5) / (3 * coin_weight))_ + Expect(uploader.CommissionRewards.String()).To(Equal(sdk.NewCoins(i.ACoin(1004), i.BCoin(1987), i.CCoin(2974)).String())) + // assert uploader self delegation rewards (here we round up since the result of delegation rewards is the remainder minus the truncated commission rewards) + // (coin_amount_per_bundle - (coin_amount_per_bundle * 0.01) - _((100 * 0.5) / (3 * coin_weight))_) * (1 - 0.1) + Expect(s.App().DelegationKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_0, i.STAKER_0).String()).To(Equal(sdk.NewCoins(i.ACoin(8896), i.BCoin(17813), i.CCoin(26726)).String())) - uploaderPayoutReward := totalUploaderReward.Mul(uploader.Commission) - uploaderDelegationReward := totalUploaderReward.Sub(uploaderPayoutReward) + fundingState, _ := s.App().FundersKeeper.GetFundingState(s.Ctx(), 0) + + // assert treasury payout + c2 := s.GetCoinsFromCommunityPool() + Expect(c2.Sub(c1...).AmountOf(i.A_DENOM).Uint64()).To(Equal(uint64(100))) + Expect(c2.Sub(c1...).AmountOf(i.B_DENOM).Uint64()).To(Equal(uint64(200))) + Expect(c2.Sub(c1...).AmountOf(i.C_DENOM).Uint64()).To(Equal(uint64(300))) + + // assert total pool funds + Expect(s.App().FundersKeeper.GetTotalActiveFunding(s.Ctx(), fundingState.PoolId).String()).To(Equal(sdk.NewCoins(i.ACoin(100*i.T_KYVE-amountPerBundle), i.BCoin(200*i.T_KYVE-2*amountPerBundle), i.CCoin(300*i.T_KYVE-3*amountPerBundle)).String())) + Expect(fundingState.ActiveFunderAddresses).To(HaveLen(1)) + }) + + It("Produce a valid bundle with multiple validators, multiple coins which are not enough for the storage reward and no foreign delegations", func() { + // ARRANGE + // set coin weight of ccoin to a very low value so amount_per_bundle of ccoin can not cover the storage reward + s.App().FundersKeeper.SetParams(s.Ctx(), fundersTypes.NewParams([]*fundersTypes.WhitelistCoinEntry{ + { + CoinDenom: globalTypes.Denom, + MinFundingAmount: 10 * i.KYVE, + MinFundingAmountPerBundle: uint64(amountPerBundle), + CoinWeight: math.LegacyNewDec(1), + }, + { + CoinDenom: i.A_DENOM, + MinFundingAmount: 10 * i.KYVE, + MinFundingAmountPerBundle: uint64(amountPerBundle), + CoinWeight: math.LegacyNewDec(1), + }, + { + CoinDenom: i.B_DENOM, + MinFundingAmount: 10 * i.KYVE, + MinFundingAmountPerBundle: uint64(amountPerBundle), + CoinWeight: math.LegacyNewDec(2), + }, + { + CoinDenom: i.C_DENOM, + MinFundingAmount: 10 * i.KYVE, + MinFundingAmountPerBundle: uint64(amountPerBundle), + CoinWeight: math.LegacyMustNewDecFromStr("0.0000001"), + }, + }, 0)) + + // fund additionally to the already funded 100acoins + s.RunTxPoolSuccess(&fundersTypes.MsgFundPool{ + Creator: i.ALICE, + Amounts: sdk.NewCoins(i.BCoin(100*i.T_KYVE), i.CCoin(100*i.T_KYVE)), + AmountsPerBundle: sdk.NewCoins(i.BCoin(amountPerBundle), i.CCoin(amountPerBundle)), + }) + + s.RunTxBundlesSuccess(&bundletypes.MsgSubmitBundleProposal{ + Creator: i.VALADDRESS_0_A, + Staker: i.STAKER_0, + PoolId: 0, + StorageId: "y62A3tfbSNcNYDGoL-eXwzyV-Zc9Q0OVtDvR1biJmNI", + DataSize: 100, + DataHash: "test_hash", + FromIndex: 0, + BundleSize: 100, + FromKey: "0", + ToKey: "99", + BundleSummary: "test_value", + }) + + s.RunTxBundlesSuccess(&bundletypes.MsgVoteBundleProposal{ + Creator: i.VALADDRESS_1_A, + Staker: i.STAKER_1, + PoolId: 0, + StorageId: "y62A3tfbSNcNYDGoL-eXwzyV-Zc9Q0OVtDvR1biJmNI", + Vote: bundletypes.VOTE_TYPE_VALID, + }) + + initialBalanceStaker1 = s.GetCoinsFromAddress(i.STAKER_1) + initialBalanceValaddress1 = s.GetCoinsFromAddress(i.VALADDRESS_1_A) + + c1 := s.GetCoinsFromCommunityPool() + + s.CommitAfterSeconds(60) + + // ACT + s.RunTxBundlesSuccess(&bundletypes.MsgSubmitBundleProposal{ + Creator: i.VALADDRESS_1_A, + Staker: i.STAKER_1, + PoolId: 0, + StorageId: "P9edn0bjEfMU_lecFDIPLvGO2v2ltpFNUMWp5kgPddg", + DataSize: 100, + DataHash: "test_hash2", + FromIndex: 100, + BundleSize: 100, + FromKey: "100", + ToKey: "199", + BundleSummary: "test_value2", + }) + + // ASSERT + // check if bundle got finalized on pool + pool, poolFound := s.App().PoolKeeper.GetPool(s.Ctx(), 0) + Expect(poolFound).To(BeTrue()) + + Expect(pool.CurrentKey).To(Equal("99")) + Expect(pool.CurrentSummary).To(Equal("test_value")) + Expect(pool.CurrentIndex).To(Equal(uint64(100))) + Expect(pool.TotalBundles).To(Equal(uint64(1))) + + // check if finalized bundle got saved + finalizedBundle, finalizedBundleFound := s.App().BundlesKeeper.GetFinalizedBundle(s.Ctx(), 0, 0) + Expect(finalizedBundleFound).To(BeTrue()) + + Expect(finalizedBundle.PoolId).To(Equal(uint64(0))) + Expect(finalizedBundle.StorageId).To(Equal("y62A3tfbSNcNYDGoL-eXwzyV-Zc9Q0OVtDvR1biJmNI")) + Expect(finalizedBundle.Uploader).To(Equal(i.STAKER_0)) + Expect(finalizedBundle.FromIndex).To(Equal(uint64(0))) + Expect(finalizedBundle.ToIndex).To(Equal(uint64(100))) + Expect(finalizedBundle.FromKey).To(Equal("0")) + Expect(finalizedBundle.ToKey).To(Equal("99")) + Expect(finalizedBundle.BundleSummary).To(Equal("test_value")) + Expect(finalizedBundle.DataHash).To(Equal("test_hash")) + Expect(finalizedBundle.FinalizedAt).NotTo(BeZero()) + Expect(finalizedBundle.StakeSecurity.ValidVotePower).To(Equal(200 * i.KYVE)) + Expect(finalizedBundle.StakeSecurity.TotalVotePower).To(Equal(200 * i.KYVE)) + + // check if next bundle proposal got registered + bundleProposal, bundleProposalFound := s.App().BundlesKeeper.GetBundleProposal(s.Ctx(), 0) + Expect(bundleProposalFound).To(BeTrue()) + + Expect(bundleProposal.PoolId).To(Equal(uint64(0))) + Expect(bundleProposal.StorageId).To(Equal("P9edn0bjEfMU_lecFDIPLvGO2v2ltpFNUMWp5kgPddg")) + Expect(bundleProposal.Uploader).To(Equal(i.STAKER_1)) + Expect(bundleProposal.NextUploader).NotTo(BeEmpty()) + Expect(bundleProposal.DataSize).To(Equal(uint64(100))) + Expect(bundleProposal.DataHash).To(Equal("test_hash2")) + Expect(bundleProposal.BundleSize).To(Equal(uint64(100))) + Expect(bundleProposal.FromKey).To(Equal("100")) + Expect(bundleProposal.ToKey).To(Equal("199")) + Expect(bundleProposal.BundleSummary).To(Equal("test_value2")) + Expect(bundleProposal.UpdatedAt).NotTo(BeZero()) + Expect(bundleProposal.VotersValid).To(ContainElement(i.STAKER_1)) + Expect(bundleProposal.VotersInvalid).To(BeEmpty()) + Expect(bundleProposal.VotersAbstain).To(BeEmpty()) + + // check uploader status + valaccountUploader, _ := s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_0) + Expect(valaccountUploader.Points).To(BeZero()) + + balanceUploaderValaddress := s.GetCoinsFromAddress(valaccountUploader.Valaddress) + Expect(balanceUploaderValaddress).To(Equal(initialBalanceValaddress0)) + + // check voter status + valaccountVoter, _ := s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_1) + Expect(valaccountVoter.Points).To(BeZero()) + + balanceVoterValaddress := s.GetCoinsFromAddress(valaccountVoter.Valaddress) + Expect(balanceVoterValaddress).To(Equal(initialBalanceValaddress1)) + + balanceVoter := s.GetCoinsFromAddress(valaccountVoter.Staker) + Expect(balanceVoter).To(Equal(initialBalanceStaker1)) + + // check uploader rewards + uploader, _ := s.App().StakersKeeper.GetStaker(s.Ctx(), valaccountUploader.Staker) + balanceUploader := s.GetCoinsFromAddress(valaccountUploader.Staker) - // assert storage reward -> 0.9 * 100 - Expect(storageReward.TruncateInt64()).To(Equal(int64(90))) // assert payout transfer - Expect(balanceUploader).To(Equal(initialBalanceStaker0)) - // assert commission rewards - Expect(uploader.CommissionRewards.AmountOf(globalTypes.Denom).Uint64()).To(Equal(uint64(uploaderPayoutReward.Add(storageReward).TruncateInt64()))) - // assert uploader self delegation rewards - Expect(s.App().DelegationKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_0, i.STAKER_0).AmountOf(globalTypes.Denom).Uint64()).To(Equal(uint64(uploaderDelegationReward.TruncateInt64()))) + Expect(balanceUploader.String()).To(Equal(initialBalanceStaker0.String())) + // assert commission rewards (here we round down since the result of commission rewards gets truncated) + // (10_000 - (10_000 * 0.01) - _((100 * 0.5) / (3 * coin_weight))_) * 0.1 + _((100 * 0.5) / (3 * coin_weight))_ + Expect(uploader.CommissionRewards.String()).To(Equal(sdk.NewCoins(i.ACoin(1004), i.BCoin(997), i.CCoin(9900)).String())) + // assert uploader self delegation rewards (here we round up since the result of delegation rewards is the remainder minus the truncated commission rewards) + // (10_000 - (10_000 * 0.01) - _((100 * 0.5) / (3 * coin_weight))_) * (1 - 0.1) + Expect(s.App().DelegationKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_0, i.STAKER_0).String()).To(Equal(sdk.NewCoins(i.ACoin(8896), i.BCoin(8903)).String())) + + fundingState, _ := s.App().FundersKeeper.GetFundingState(s.Ctx(), 0) + + // assert treasury payout + c2 := s.GetCoinsFromCommunityPool() + Expect(c2.Sub(c1...).AmountOf(i.A_DENOM).Uint64()).To(Equal(uint64(100))) + Expect(c2.Sub(c1...).AmountOf(i.B_DENOM).Uint64()).To(Equal(uint64(100))) + Expect(c2.Sub(c1...).AmountOf(i.C_DENOM).Uint64()).To(Equal(uint64(100))) + + // assert total pool funds + Expect(s.App().FundersKeeper.GetTotalActiveFunding(s.Ctx(), fundingState.PoolId).String()).To(Equal(sdk.NewCoins(i.ACoin(100*i.T_KYVE-amountPerBundle), i.BCoin(100*i.T_KYVE-amountPerBundle), i.CCoin(100*i.T_KYVE-amountPerBundle)).String())) + Expect(fundingState.ActiveFunderAddresses).To(HaveLen(1)) + }) + + It("Produce a valid bundle with multiple validator, multiple coins and no foreign delegations where one coin is removed from the whitelist", func() { + // ARRANGE + // fund additionally to the already funded 100acoins + s.RunTxPoolSuccess(&fundersTypes.MsgFundPool{ + Creator: i.ALICE, + Amounts: sdk.NewCoins(i.BCoin(100*i.T_KYVE), i.CCoin(100*i.T_KYVE)), + AmountsPerBundle: sdk.NewCoins(i.BCoin(amountPerBundle), i.CCoin(amountPerBundle)), + }) + + // remove ccoin from whitelist + s.App().FundersKeeper.SetParams(s.Ctx(), fundersTypes.NewParams([]*fundersTypes.WhitelistCoinEntry{ + { + CoinDenom: globalTypes.Denom, + MinFundingAmount: 10 * i.KYVE, + MinFundingAmountPerBundle: uint64(amountPerBundle), + CoinWeight: math.LegacyNewDec(1), + }, + { + CoinDenom: i.A_DENOM, + MinFundingAmount: 10 * i.KYVE, + MinFundingAmountPerBundle: uint64(amountPerBundle), + CoinWeight: math.LegacyNewDec(1), + }, + { + CoinDenom: i.B_DENOM, + MinFundingAmount: 10 * i.KYVE, + MinFundingAmountPerBundle: uint64(amountPerBundle), + CoinWeight: math.LegacyNewDec(2), + }, + }, 0)) + + s.RunTxBundlesSuccess(&bundletypes.MsgSubmitBundleProposal{ + Creator: i.VALADDRESS_0_A, + Staker: i.STAKER_0, + PoolId: 0, + StorageId: "y62A3tfbSNcNYDGoL-eXwzyV-Zc9Q0OVtDvR1biJmNI", + DataSize: 100, + DataHash: "test_hash", + FromIndex: 0, + BundleSize: 100, + FromKey: "0", + ToKey: "99", + BundleSummary: "test_value", + }) + + s.RunTxBundlesSuccess(&bundletypes.MsgVoteBundleProposal{ + Creator: i.VALADDRESS_1_A, + Staker: i.STAKER_1, + PoolId: 0, + StorageId: "y62A3tfbSNcNYDGoL-eXwzyV-Zc9Q0OVtDvR1biJmNI", + Vote: bundletypes.VOTE_TYPE_VALID, + }) + + initialBalanceStaker1 = s.GetCoinsFromAddress(i.STAKER_1) + initialBalanceValaddress1 = s.GetCoinsFromAddress(i.VALADDRESS_1_A) + + c1 := s.GetCoinsFromCommunityPool() + + s.CommitAfterSeconds(60) + + // ACT + s.RunTxBundlesSuccess(&bundletypes.MsgSubmitBundleProposal{ + Creator: i.VALADDRESS_1_A, + Staker: i.STAKER_1, + PoolId: 0, + StorageId: "P9edn0bjEfMU_lecFDIPLvGO2v2ltpFNUMWp5kgPddg", + DataSize: 100, + DataHash: "test_hash2", + FromIndex: 100, + BundleSize: 100, + FromKey: "100", + ToKey: "199", + BundleSummary: "test_value2", + }) + + // ASSERT + // check if bundle got finalized on pool + pool, poolFound := s.App().PoolKeeper.GetPool(s.Ctx(), 0) + Expect(poolFound).To(BeTrue()) + + Expect(pool.CurrentKey).To(Equal("99")) + Expect(pool.CurrentSummary).To(Equal("test_value")) + Expect(pool.CurrentIndex).To(Equal(uint64(100))) + Expect(pool.TotalBundles).To(Equal(uint64(1))) + + // check if finalized bundle got saved + finalizedBundle, finalizedBundleFound := s.App().BundlesKeeper.GetFinalizedBundle(s.Ctx(), 0, 0) + Expect(finalizedBundleFound).To(BeTrue()) + + Expect(finalizedBundle.PoolId).To(Equal(uint64(0))) + Expect(finalizedBundle.StorageId).To(Equal("y62A3tfbSNcNYDGoL-eXwzyV-Zc9Q0OVtDvR1biJmNI")) + Expect(finalizedBundle.Uploader).To(Equal(i.STAKER_0)) + Expect(finalizedBundle.FromIndex).To(Equal(uint64(0))) + Expect(finalizedBundle.ToIndex).To(Equal(uint64(100))) + Expect(finalizedBundle.FromKey).To(Equal("0")) + Expect(finalizedBundle.ToKey).To(Equal("99")) + Expect(finalizedBundle.BundleSummary).To(Equal("test_value")) + Expect(finalizedBundle.DataHash).To(Equal("test_hash")) + Expect(finalizedBundle.FinalizedAt).NotTo(BeZero()) + Expect(finalizedBundle.StakeSecurity.ValidVotePower).To(Equal(200 * i.KYVE)) + Expect(finalizedBundle.StakeSecurity.TotalVotePower).To(Equal(200 * i.KYVE)) + + // check if next bundle proposal got registered + bundleProposal, bundleProposalFound := s.App().BundlesKeeper.GetBundleProposal(s.Ctx(), 0) + Expect(bundleProposalFound).To(BeTrue()) + + Expect(bundleProposal.PoolId).To(Equal(uint64(0))) + Expect(bundleProposal.StorageId).To(Equal("P9edn0bjEfMU_lecFDIPLvGO2v2ltpFNUMWp5kgPddg")) + Expect(bundleProposal.Uploader).To(Equal(i.STAKER_1)) + Expect(bundleProposal.NextUploader).NotTo(BeEmpty()) + Expect(bundleProposal.DataSize).To(Equal(uint64(100))) + Expect(bundleProposal.DataHash).To(Equal("test_hash2")) + Expect(bundleProposal.BundleSize).To(Equal(uint64(100))) + Expect(bundleProposal.FromKey).To(Equal("100")) + Expect(bundleProposal.ToKey).To(Equal("199")) + Expect(bundleProposal.BundleSummary).To(Equal("test_value2")) + Expect(bundleProposal.UpdatedAt).NotTo(BeZero()) + Expect(bundleProposal.VotersValid).To(ContainElement(i.STAKER_1)) + Expect(bundleProposal.VotersInvalid).To(BeEmpty()) + Expect(bundleProposal.VotersAbstain).To(BeEmpty()) + + // check uploader status + valaccountUploader, _ := s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_0) + Expect(valaccountUploader.Points).To(BeZero()) + + balanceUploaderValaddress := s.GetCoinsFromAddress(valaccountUploader.Valaddress) + Expect(balanceUploaderValaddress).To(Equal(initialBalanceValaddress0)) + + // check voter status + valaccountVoter, _ := s.App().StakersKeeper.GetValaccount(s.Ctx(), 0, i.STAKER_1) + Expect(valaccountVoter.Points).To(BeZero()) + + balanceVoterValaddress := s.GetCoinsFromAddress(valaccountVoter.Valaddress) + Expect(balanceVoterValaddress).To(Equal(initialBalanceValaddress1)) + + balanceVoter := s.GetCoinsFromAddress(valaccountVoter.Staker) + Expect(balanceVoter).To(Equal(initialBalanceStaker1)) + + // check uploader rewards + uploader, _ := s.App().StakersKeeper.GetStaker(s.Ctx(), valaccountUploader.Staker) + balanceUploader := s.GetCoinsFromAddress(valaccountUploader.Staker) + + // assert payout transfer + Expect(balanceUploader.String()).To(Equal(initialBalanceStaker0.String())) + // assert commission rewards (here we round down since the result of commission rewards gets truncated) + // (10_000 - (10_000 * 0.01) - _((100 * 0.5) / (2 * coin_weight))_) * 0.1 + _((100 * 0.5) / (2 * coin_weight))_ + Expect(uploader.CommissionRewards.String()).To(Equal(sdk.NewCoins(i.ACoin(1012), i.BCoin(1000)).String())) + // assert uploader self delegation rewards (here we round up since the result of delegation rewards is the remainder minus the truncated commission rewards) + // (10_000 - (10_000 * 0.01) - _((100 * 0.5) / (2 * coin_weight))_) * (1 - 0.1) + Expect(s.App().DelegationKeeper.GetOutstandingRewards(s.Ctx(), i.STAKER_0, i.STAKER_0).String()).To(Equal(sdk.NewCoins(i.ACoin(8888), i.BCoin(8900)).String())) fundingState, _ := s.App().FundersKeeper.GetFundingState(s.Ctx(), 0) + // assert treasury payout + c2 := s.GetCoinsFromCommunityPool() + Expect(c2.Sub(c1...).AmountOf(i.A_DENOM).Uint64()).To(Equal(uint64(100))) + Expect(c2.Sub(c1...).AmountOf(i.B_DENOM).Uint64()).To(Equal(uint64(100))) + Expect(c2.Sub(c1...).AmountOf(i.C_DENOM).Uint64()).To(BeZero()) + // assert total pool funds - Expect(s.App().FundersKeeper.GetTotalActiveFunding(s.Ctx(), fundingState.PoolId)[0].Amount.Uint64()).To(Equal(100*i.KYVE - 1*amountPerBundle)) + Expect(s.App().FundersKeeper.GetTotalActiveFunding(s.Ctx(), fundingState.PoolId).String()).To(Equal(sdk.NewCoins(i.ACoin(100*i.T_KYVE-amountPerBundle), i.BCoin(100*i.T_KYVE-amountPerBundle), i.CCoin(100*i.T_KYVE)).String())) Expect(fundingState.ActiveFunderAddresses).To(HaveLen(1)) }) }) diff --git a/x/stakers/spec/03_messages.md b/x/stakers/spec/03_messages.md index ece28b35..f9aac8df 100644 --- a/x/stakers/spec/03_messages.md +++ b/x/stakers/spec/03_messages.md @@ -33,7 +33,7 @@ can be multiple coins. ## `MsgJoinPool` -This message allows a staker to join a pool. For joining a pool the staker must +This message allows a staker to join a pool. For joining a pool, the staker must provide the poolId and an address which is operated by the protocol node. This address is allowed to vote in favor of the staker. If this address misbehaves, the staker will get slashed. The message also takes an amount as an argument