From 96d1dec14c3d890e81f03470af074e381466c2b9 Mon Sep 17 00:00:00 2001 From: Tuan Tran Date: Wed, 20 Nov 2024 08:15:56 +0700 Subject: [PATCH 1/7] update --- custom/auth/ante/fee_test.go | 214 ++++++++++++++++++--------- custom/auth/ante/integration_test.go | 4 +- 2 files changed, 149 insertions(+), 69 deletions(-) diff --git a/custom/auth/ante/fee_test.go b/custom/auth/ante/fee_test.go index bb094edb..e346d7a9 100644 --- a/custom/auth/ante/fee_test.go +++ b/custom/auth/ante/fee_test.go @@ -2,7 +2,6 @@ package ante_test import ( "encoding/json" - "fmt" "os" "time" @@ -573,6 +572,22 @@ func (s *AnteTestSuite) TestTaxExemption() { minFeeAmount: feeAmt, expectProceeds: feeAmt, expectReverseCharge: false, + }, + { + name: "MsgSend(normal -> normal), non-zero not enough", + msgSigner: privs[2], + msgCreator: func() []sdk.Msg { + var msgs []sdk.Msg + + msg1 := banktypes.NewMsgSend(addrs[2], addrs[3], sdk.NewCoins(sendCoin)) + msgs = append(msgs, msg1) + + return msgs + }, + // don't tax this because we are not sending enough + minFeeAmount: feeAmt / 2, + expectProceeds: 0, + expectReverseCharge: true, }, { name: "MsgSend(normal -> normal, reverse charge)", msgSigner: privs[2], @@ -585,7 +600,7 @@ func (s *AnteTestSuite) TestTaxExemption() { return msgs }, // tax this one hence burn amount is fee amount - minFeeAmount: 0, + minFeeAmount: 1000, expectProceeds: 0, expectReverseCharge: true, }, { @@ -603,7 +618,24 @@ func (s *AnteTestSuite) TestTaxExemption() { minFeeAmount: feeAmt, expectProceeds: feeAmt, expectReverseCharge: false, - }, { + }, + { + name: "MsgExec(MsgSend(normal -> normal))", + msgSigner: privs[2], + msgCreator: func() []sdk.Msg { + var msgs []sdk.Msg + + msg1 := authz.NewMsgExec(addrs[1], []sdk.Msg{banktypes.NewMsgSend(addrs[2], addrs[3], sdk.NewCoins(sendCoin))}) + msgs = append(msgs, &msg1) + + return msgs + }, + // tax this one hence burn amount is fee amount + minFeeAmount: feeAmt, + expectProceeds: feeAmt, + expectReverseCharge: false, + }, + { name: "MsgSend(exemption -> normal), MsgSend(exemption -> exemption)", msgSigner: privs[0], msgCreator: func() []sdk.Msg { @@ -709,75 +741,123 @@ func (s *AnteTestSuite) TestTaxExemption() { expectProceeds: 0, expectReverseCharge: false, }, + + { + name: "MsgExecuteContract(exemption), MsgExecuteContract(normal)", + msgSigner: privs[3], + msgCreator: func() []sdk.Msg { + sendAmount := int64(1000000) + sendCoins := sdk.NewCoins(sdk.NewInt64Coin(core.MicroSDRDenom, sendAmount)) + // get wasm code for wasm contract create and instantiate + wasmCode, err := os.ReadFile("./testdata/hackatom.wasm") + s.Require().NoError(err) + per := wasmkeeper.NewDefaultPermissionKeeper(s.app.WasmKeeper) + // set wasm default params + s.app.WasmKeeper.SetParams(s.ctx, wasmtypes.DefaultParams()) + // wasm create + CodeID, _, err := per.Create(s.ctx, addrs[0], wasmCode, nil) + s.Require().NoError(err) + // params for contract init + r := wasmkeeper.HackatomExampleInitMsg{Verifier: addrs[0], Beneficiary: addrs[0]} + bz, err := json.Marshal(r) + s.Require().NoError(err) + // change block time for contract instantiate + s.ctx = s.ctx.WithBlockTime(time.Date(2020, time.April, 22, 12, 0, 0, 0, time.UTC)) + // instantiate contract then not set to tax exemption + addr, _, err := per.Instantiate(s.ctx, CodeID, addrs[0], nil, bz, "my label", nil) + s.Require().NoError(err) + + var msgs []sdk.Msg + // msg and signatures + msg1 := &wasmtypes.MsgExecuteContract{ + Sender: addrs[0].String(), + Contract: addr.String(), + Msg: []byte{}, + Funds: sendCoins, + } + msgs = append(msgs, msg1) + + msg2 := banktypes.NewMsgSend(addrs[2], addrs[3], sdk.NewCoins(sendCoin)) + + msgs = append(msgs, msg2) + return msgs + }, + minFeeAmount: feeAmt, + expectProceeds: feeAmt, + expectReverseCharge: false, + }, } // there should be no coin in burn module // run once with reverse charge and once without for _, c := range cases { - s.SetupTest(true) // setup - require := s.Require() - tk := s.app.TreasuryKeeper - ak := s.app.AccountKeeper - bk := s.app.BankKeeper - burnTaxRate := sdk.NewDecWithPrec(5, 3) - burnSplitRate := sdk.NewDecWithPrec(5, 1) - oracleSplitRate := sdk.ZeroDec() - - // Set burn split rate to 50% - // oracle split to 0% (oracle split is covered in another test) - tk.SetBurnSplitRate(s.ctx, burnSplitRate) - tk.SetOracleSplitRate(s.ctx, oracleSplitRate) - - fmt.Printf("CASE = %s \n", c.name) - s.txBuilder = s.clientCtx.TxConfig.NewTxBuilder() - - tk.AddBurnTaxExemptionAddress(s.ctx, addrs[0].String()) - tk.AddBurnTaxExemptionAddress(s.ctx, addrs[1].String()) - - mfd := ante.NewFeeDecorator(s.app.AccountKeeper, s.app.BankKeeper, s.app.FeeGrantKeeper, s.app.TreasuryKeeper, s.app.DistrKeeper, s.app.TaxKeeper) - antehandler := sdk.ChainAnteDecorators(mfd) - pd := post.NewTaxDecorator(s.app.TaxKeeper, bk, ak, tk) - posthandler := sdk.ChainPostDecorators(pd) - - for i := 0; i < 4; i++ { - coins := sdk.NewCoins(sdk.NewCoin(core.MicroSDRDenom, sdk.NewInt(10000000))) - testutil.FundAccount(s.app.BankKeeper, s.ctx, addrs[i], coins) - } - - // msg and signatures - feeAmount := sdk.NewCoins(sdk.NewInt64Coin(core.MicroSDRDenom, c.minFeeAmount)) - gasLimit := testdata.NewTestGasLimit() - require.NoError(s.txBuilder.SetMsgs(c.msgCreator()...)) - s.txBuilder.SetFeeAmount(feeAmount) - s.txBuilder.SetGasLimit(gasLimit) - - privs, accNums, accSeqs := []cryptotypes.PrivKey{c.msgSigner}, []uint64{0}, []uint64{0} - tx, err := s.CreateTestTx(privs, accNums, accSeqs, s.ctx.ChainID()) - require.NoError(err) - - newCtx, err := antehandler(s.ctx, tx, false) - require.NoError(err) - newCtx, err = posthandler(newCtx, tx, false, true) - require.NoError(err) - - actualTaxRate := s.app.TaxKeeper.GetBurnTaxRate(s.ctx) - require.Equal(burnTaxRate, actualTaxRate) - - require.Equal(c.expectReverseCharge, newCtx.Value(taxtypes.ContextKeyTaxReverseCharge)) - - // check fee collector - feeCollector := ak.GetModuleAccount(s.ctx, authtypes.FeeCollectorName) - amountFee := bk.GetBalance(s.ctx, feeCollector.GetAddress(), core.MicroSDRDenom) - if c.expectReverseCharge { - // tax is NOT split in this case in the ante handler - require.Equal(amountFee, sdk.NewCoin(core.MicroSDRDenom, sdk.NewInt(c.minFeeAmount))) - } else { - require.Equal(amountFee, sdk.NewCoin(core.MicroSDRDenom, sdk.NewDec(c.minFeeAmount).Mul(burnSplitRate).TruncateInt())) - } - - // check tax proceeds - taxProceeds := s.app.TreasuryKeeper.PeekEpochTaxProceeds(s.ctx) - require.Equal(taxProceeds, sdk.NewCoins(sdk.NewCoin(core.MicroSDRDenom, sdk.NewInt(c.expectProceeds)))) + + s.Run(c.name, func() { + s.SetupTest(true) // setup + require := s.Require() + tk := s.app.TreasuryKeeper + ak := s.app.AccountKeeper + bk := s.app.BankKeeper + burnTaxRate := sdk.NewDecWithPrec(5, 3) + burnSplitRate := sdk.NewDecWithPrec(5, 1) + oracleSplitRate := sdk.ZeroDec() + + // Set burn split rate to 50% + // oracle split to 0% (oracle split is covered in another test) + tk.SetBurnSplitRate(s.ctx, burnSplitRate) + tk.SetOracleSplitRate(s.ctx, oracleSplitRate) + + s.txBuilder = s.clientCtx.TxConfig.NewTxBuilder() + + tk.AddBurnTaxExemptionAddress(s.ctx, addrs[0].String()) + tk.AddBurnTaxExemptionAddress(s.ctx, addrs[1].String()) + + mfd := ante.NewFeeDecorator(s.app.AccountKeeper, s.app.BankKeeper, s.app.FeeGrantKeeper, s.app.TreasuryKeeper, s.app.DistrKeeper, s.app.TaxKeeper) + antehandler := sdk.ChainAnteDecorators(mfd) + pd := post.NewTaxDecorator(s.app.TaxKeeper, bk, ak, tk) + posthandler := sdk.ChainPostDecorators(pd) + + for i := 0; i < 4; i++ { + coins := sdk.NewCoins(sdk.NewCoin(core.MicroSDRDenom, sdk.NewInt(10000000))) + testutil.FundAccount(s.app.BankKeeper, s.ctx, addrs[i], coins) + } + + // msg and signatures + feeAmount := sdk.NewCoins(sdk.NewInt64Coin(core.MicroSDRDenom, c.minFeeAmount)) + gasLimit := testdata.NewTestGasLimit() + require.NoError(s.txBuilder.SetMsgs(c.msgCreator()...)) + s.txBuilder.SetFeeAmount(feeAmount) + s.txBuilder.SetGasLimit(gasLimit) + + privs, accNums, accSeqs := []cryptotypes.PrivKey{c.msgSigner}, []uint64{0}, []uint64{0} + tx, err := s.CreateTestTx(privs, accNums, accSeqs, s.ctx.ChainID()) + require.NoError(err) + + newCtx, err := antehandler(s.ctx, tx, false) + require.NoError(err) + newCtx, err = posthandler(newCtx, tx, false, true) + require.NoError(err) + + actualTaxRate := s.app.TaxKeeper.GetBurnTaxRate(s.ctx) + require.Equal(burnTaxRate, actualTaxRate) + + require.Equal(c.expectReverseCharge, newCtx.Value(taxtypes.ContextKeyTaxReverseCharge)) + + // check fee collector + feeCollector := ak.GetModuleAccount(s.ctx, authtypes.FeeCollectorName) + amountFee := bk.GetBalance(s.ctx, feeCollector.GetAddress(), core.MicroSDRDenom) + if c.expectReverseCharge { + // tax is NOT split in this case in the ante handler + require.Equal(amountFee, sdk.NewCoin(core.MicroSDRDenom, sdk.NewInt(c.minFeeAmount))) + } else { + require.Equal(amountFee, sdk.NewCoin(core.MicroSDRDenom, sdk.NewDec(c.minFeeAmount).Mul(burnSplitRate).TruncateInt())) + } + + // check tax proceeds + taxProceeds := s.app.TreasuryKeeper.PeekEpochTaxProceeds(s.ctx) + require.Equal(sdk.NewCoins(sdk.NewCoin(core.MicroSDRDenom, sdk.NewInt(c.expectProceeds))), taxProceeds) + }) + } } diff --git a/custom/auth/ante/integration_test.go b/custom/auth/ante/integration_test.go index dc02a5a5..3b4edec8 100644 --- a/custom/auth/ante/integration_test.go +++ b/custom/auth/ante/integration_test.go @@ -35,7 +35,7 @@ func (s *AnteTestSuite) TestIntegrationTaxExemption() { // set send amount sendAmt := int64(1_000_000) sendCoin := sdk.NewInt64Coin(core.MicroSDRDenom, sendAmt) - feeAmt := int64(1000) + feeAmt := int64(5000) cases := []struct { name string @@ -179,7 +179,7 @@ func (s *AnteTestSuite) TestIntegrationTaxExemption() { // case 1 provides zero fee so not enough fee // case 2 provides enough fee feeCases := []int64{0, feeAmt} - for i := 0; i < 1; i++ { + for i := 0; i <= 1; i++ { feeAmount := sdk.NewCoins(sdk.NewInt64Coin(core.MicroSDRDenom, feeCases[i])) gasLimit := testdata.NewTestGasLimit() s.Require().NoError(s.txBuilder.SetMsgs(c.msgCreator()...)) From f48bef8342713bdd77732ef0cadc1bc8d9ef838e Mon Sep 17 00:00:00 2001 From: Tuan Tran Date: Wed, 20 Nov 2024 22:07:14 +0700 Subject: [PATCH 2/7] wip: add tests --- custom/auth/ante/fee.go | 4 +- custom/auth/ante/fee_test.go | 181 +++++++++++++++++++++++++++++++++++ 2 files changed, 183 insertions(+), 2 deletions(-) diff --git a/custom/auth/ante/fee.go b/custom/auth/ante/fee.go index fe908550..229f4950 100644 --- a/custom/auth/ante/fee.go +++ b/custom/auth/ante/fee.go @@ -260,9 +260,9 @@ func (fd FeeDecorator) checkTxFee(ctx sdk.Context, tx sdk.Tx, taxes sdk.Coins, n allFees := requiredFees.Add(nonTaxableTaxes...) // Check required fees - if !requiredFees.IsZero() && !feeCoins.IsAnyGTE(requiredFees) { + if !requiredFees.IsZero() && !feeCoins.IsAllGTE(requiredFees) { // we don't have enough for tax and gas fees. But do we have enough for gas alone? - if !requiredGasFees.IsZero() && !feeCoins.IsAnyGTE(requiredGasFees) { + if !requiredGasFees.IsZero() && !feeCoins.IsAllGTE(requiredGasFees) { return 0, false, false, errorsmod.Wrapf(sdkerrors.ErrInsufficientFee, "insufficient fees; got: %q, required: %q = %q(gas) + %q(stability)", feeCoins, requiredFees, requiredGasFees, taxes) } diff --git a/custom/auth/ante/fee_test.go b/custom/auth/ante/fee_test.go index e346d7a9..2a687218 100644 --- a/custom/auth/ante/fee_test.go +++ b/custom/auth/ante/fee_test.go @@ -859,6 +859,187 @@ func (s *AnteTestSuite) TestTaxExemption() { }) } + +} + +func (s *AnteTestSuite) TestTaxExemptionWithMultipleDenoms() { + // keys and addresses + var privs []cryptotypes.PrivKey + var addrs []sdk.AccAddress + + // 0, 1: exemption + // 2, 3: normal + for i := 0; i < 4; i++ { + priv, _, addr := testdata.KeyTestPubAddr() + privs = append(privs, priv) + addrs = append(addrs, addr) + } + + // use two different denoms but with same gas price + denom1 := "uaad" + denom2 := "ucud" + + // set send amount + sendAmt := int64(1000000) + sendCoin := sdk.NewInt64Coin(denom1, sendAmt) + anotherSendCoin := sdk.NewInt64Coin(denom2, sendAmt) + + cases := []struct { + name string + msgSigner cryptotypes.PrivKey + msgCreator func() []sdk.Msg + minFeeAmounts []sdk.Coin + expectProceeds sdk.Coins + expectReverseCharge bool + }{ + { + name: "MsgSend(exemption -> exemption) with multiple fee denoms", + msgSigner: privs[0], + msgCreator: func() []sdk.Msg { + var msgs []sdk.Msg + msg1 := banktypes.NewMsgSend(addrs[0], addrs[1], sdk.NewCoins(sendCoin)) + msgs = append(msgs, msg1) + return msgs + }, + minFeeAmounts: []sdk.Coin{ + sdk.NewInt64Coin(denom1, 0), + sdk.NewInt64Coin(denom2, 0), + }, + expectProceeds: sdk.NewCoins(), + expectReverseCharge: false, + }, + { + name: "MsgSend(normal -> normal) with multiple fee denoms", + msgSigner: privs[2], + msgCreator: func() []sdk.Msg { + var msgs []sdk.Msg + msg1 := banktypes.NewMsgSend(addrs[2], addrs[3], sdk.NewCoins(sendCoin, anotherSendCoin)) + msgs = append(msgs, msg1) + return msgs + }, + minFeeAmounts: []sdk.Coin{ + sdk.NewInt64Coin(denom1, 5000), + sdk.NewInt64Coin(denom2, 5000), + }, + expectProceeds: sdk.NewCoins( + sdk.NewInt64Coin(denom1, 5000), + sdk.NewInt64Coin(denom2, 5000), + ), + expectReverseCharge: false, + }, + { + name: "MsgSend(normal -> normal), enough taxes for both denoms", + msgSigner: privs[2], + msgCreator: func() []sdk.Msg { + var msgs []sdk.Msg + msg1 := banktypes.NewMsgSend(addrs[2], addrs[3], sdk.NewCoins(sendCoin, anotherSendCoin)) + msgs = append(msgs, msg1) + return msgs + }, + minFeeAmounts: []sdk.Coin{ + sdk.NewInt64Coin(denom1, 5000), + sdk.NewInt64Coin(denom2, 5000), + }, + expectProceeds: []sdk.Coin{ + sdk.NewInt64Coin(denom1, 5000), + sdk.NewInt64Coin(denom2, 5000), + }, + expectReverseCharge: false, + }, + { + name: "MsgSend(normal -> normal), one denom not enough tax", + msgSigner: privs[2], + msgCreator: func() []sdk.Msg { + var msgs []sdk.Msg + msg1 := banktypes.NewMsgSend(addrs[2], addrs[3], sdk.NewCoins(sendCoin, anotherSendCoin)) + msgs = append(msgs, msg1) + return msgs + }, + minFeeAmounts: []sdk.Coin{ + sdk.NewInt64Coin(denom1, 5000), + sdk.NewInt64Coin(denom2, 2500), + }, + expectProceeds: []sdk.Coin{}, + expectReverseCharge: true, + }, + } + + for _, c := range cases { + s.Run(c.name, func() { + s.SetupTest(true) // setup + require := s.Require() + tk := s.app.TreasuryKeeper + ak := s.app.AccountKeeper + bk := s.app.BankKeeper + + burnTaxRate := sdk.NewDecWithPrec(5, 3) + burnSplitRate := sdk.NewDecWithPrec(5, 1) + oracleSplitRate := sdk.ZeroDec() + + // Set burn split rate to 50% + tk.SetBurnSplitRate(s.ctx, burnSplitRate) + tk.SetOracleSplitRate(s.ctx, oracleSplitRate) + + s.txBuilder = s.clientCtx.TxConfig.NewTxBuilder() + + tk.AddBurnTaxExemptionAddress(s.ctx, addrs[0].String()) + tk.AddBurnTaxExemptionAddress(s.ctx, addrs[1].String()) + + mfd := ante.NewFeeDecorator(s.app.AccountKeeper, s.app.BankKeeper, s.app.FeeGrantKeeper, s.app.TreasuryKeeper, s.app.DistrKeeper, s.app.TaxKeeper) + antehandler := sdk.ChainAnteDecorators(mfd) + pd := post.NewTaxDecorator(s.app.TaxKeeper, bk, ak, tk) + posthandler := sdk.ChainPostDecorators(pd) + + // Fund accounts with both denoms + for i := 0; i < 4; i++ { + coins := sdk.NewCoins( + sdk.NewCoin(denom1, sdk.NewInt(10000000)), + sdk.NewCoin(denom2, sdk.NewInt(10000000)), + ) + testutil.FundAccount(s.app.BankKeeper, s.ctx, addrs[i], coins) + } + + // Set up transaction with multiple fee denoms + feeAmount := sdk.NewCoins(c.minFeeAmounts...) + gasLimit := testdata.NewTestGasLimit() + require.NoError(s.txBuilder.SetMsgs(c.msgCreator()...)) + s.txBuilder.SetFeeAmount(feeAmount) + s.txBuilder.SetGasLimit(gasLimit) + + privs, accNums, accSeqs := []cryptotypes.PrivKey{c.msgSigner}, []uint64{0}, []uint64{0} + tx, err := s.CreateTestTx(privs, accNums, accSeqs, s.ctx.ChainID()) + require.NoError(err) + + newCtx, err := antehandler(s.ctx, tx, false) + require.NoError(err) + newCtx, err = posthandler(newCtx, tx, false, true) + require.NoError(err) + + actualTaxRate := s.app.TaxKeeper.GetBurnTaxRate(s.ctx) + require.Equal(burnTaxRate, actualTaxRate) + + require.Equal(c.expectReverseCharge, newCtx.Value(taxtypes.ContextKeyTaxReverseCharge)) + + // Check fee collector for each denom + feeCollector := ak.GetModuleAccount(s.ctx, authtypes.FeeCollectorName) + for _, feeCoin := range c.minFeeAmounts { + amountFee := bk.GetBalance(s.ctx, feeCollector.GetAddress(), feeCoin.Denom) + if c.expectReverseCharge { + require.Equal(amountFee, feeCoin) + } else { + expectedFee := sdk.NewCoin( + feeCoin.Denom, + sdk.NewDec(feeCoin.Amount.Int64()).Mul(burnSplitRate).TruncateInt(), + ) + require.Equal(expectedFee, amountFee) + } + } + + // Check tax proceeds + taxProceeds := s.app.TreasuryKeeper.PeekEpochTaxProceeds(s.ctx) + require.Equal(c.expectProceeds, taxProceeds) + }) + } } // go test -v -run ^TestAnteTestSuite/TestBurnSplitTax$ github.com/classic-terra/core/v3/custom/auth/ante From 0c7401d01e39c779fe42492ba057dc8f4a96a7f3 Mon Sep 17 00:00:00 2001 From: Tuan Tran Date: Fri, 22 Nov 2024 16:33:42 +0700 Subject: [PATCH 3/7] update --- custom/auth/ante/fee.go | 2 +- custom/auth/ante/fee_test.go | 183 +++++++++++++++++++++++++++++++++++ 2 files changed, 184 insertions(+), 1 deletion(-) diff --git a/custom/auth/ante/fee.go b/custom/auth/ante/fee.go index 229f4950..ff5d2638 100644 --- a/custom/auth/ante/fee.go +++ b/custom/auth/ante/fee.go @@ -270,7 +270,7 @@ func (fd FeeDecorator) checkTxFee(ctx sdk.Context, tx sdk.Tx, taxes sdk.Coins, n reverseCharge = true } - if !allFees.IsZero() && feeCoins.IsAnyGTE(allFees) { + if !allFees.IsZero() && feeCoins.IsAllGTE(allFees) { // we have enough for all fees refundNonTaxableTaxes = true } diff --git a/custom/auth/ante/fee_test.go b/custom/auth/ante/fee_test.go index 2a687218..3d5f0393 100644 --- a/custom/auth/ante/fee_test.go +++ b/custom/auth/ante/fee_test.go @@ -1042,6 +1042,189 @@ func (s *AnteTestSuite) TestTaxExemptionWithMultipleDenoms() { } } +func (s *AnteTestSuite) TestTaxExemptionWithGasPriceEnabled() { + // keys and addresses + var privs []cryptotypes.PrivKey + var addrs []sdk.AccAddress + + // 0, 1: exemption + // 2, 3: normal + for i := 0; i < 4; i++ { + priv, _, addr := testdata.KeyTestPubAddr() + privs = append(privs, priv) + addrs = append(addrs, addr) + } + + // use two different denoms but with same gas price + denom1 := "uaad" + denom2 := "ucud" + + // set send amount + sendAmt := int64(1000000) + sendCoin := sdk.NewInt64Coin(denom1, sendAmt) + anotherSendCoin := sdk.NewInt64Coin(denom2, sendAmt) + denom1Price := sdk.NewDecCoinFromDec(denom1, sdk.NewDecWithPrec(10, 1)) + denom2Price := sdk.NewDecCoinFromDec(denom2, sdk.NewDecWithPrec(10, 1)) + customGasPrices := []sdk.DecCoin{denom1Price, denom2Price} + + requiredFees := sdk.NewCoins(sdk.NewInt64Coin(denom1, 200000), sdk.NewInt64Coin(denom2, 200000)) + + cases := []struct { + name string + msgSigner cryptotypes.PrivKey + msgCreator func() []sdk.Msg + minFeeAmounts []sdk.Coin + expectProceeds sdk.Coins + expectPanic bool + expectReverseCharge bool + }{ + { + name: "MsgSend(exemption -> exemption) with multiple fee denoms, not enough gas fees", + msgSigner: privs[0], + msgCreator: func() []sdk.Msg { + var msgs []sdk.Msg + msg1 := banktypes.NewMsgSend(addrs[0], addrs[1], sdk.NewCoins(sendCoin)) + msgs = append(msgs, msg1) + return msgs + }, + minFeeAmounts: []sdk.Coin{ + sdk.NewInt64Coin(denom1, 0), + sdk.NewInt64Coin(denom2, 0), + }, + expectProceeds: sdk.NewCoins(), + expectPanic: true, + expectReverseCharge: false, + }, + { + name: "MsgSend(normal -> normal) with multiple fee denoms, with enough gas fees but not enough tax", + msgSigner: privs[2], + msgCreator: func() []sdk.Msg { + var msgs []sdk.Msg + msg1 := banktypes.NewMsgSend(addrs[2], addrs[3], sdk.NewCoins(sendCoin, anotherSendCoin)) + msgs = append(msgs, msg1) + return msgs + }, + minFeeAmounts: requiredFees, + expectProceeds: sdk.NewCoins(), + expectReverseCharge: true, + }, + { + name: "MsgSend(normal -> normal), enough taxes for both denoms", + msgSigner: privs[2], + msgCreator: func() []sdk.Msg { + var msgs []sdk.Msg + msg1 := banktypes.NewMsgSend(addrs[2], addrs[3], sdk.NewCoins(sendCoin, anotherSendCoin)) + msgs = append(msgs, msg1) + return msgs + }, + minFeeAmounts: []sdk.Coin{ + sdk.NewInt64Coin(denom1, 5000), + sdk.NewInt64Coin(denom2, 5000), + }, + expectProceeds: []sdk.Coin{ + sdk.NewInt64Coin(denom1, 5000), + sdk.NewInt64Coin(denom2, 5000), + }, + expectReverseCharge: false, + }, + { + name: "MsgSend(normal -> normal), one denom not enough tax", + msgSigner: privs[2], + msgCreator: func() []sdk.Msg { + var msgs []sdk.Msg + msg1 := banktypes.NewMsgSend(addrs[2], addrs[3], sdk.NewCoins(sendCoin, anotherSendCoin)) + msgs = append(msgs, msg1) + return msgs + }, + minFeeAmounts: []sdk.Coin{ + sdk.NewInt64Coin(denom1, 5000), + sdk.NewInt64Coin(denom2, 2500), + }, + expectProceeds: []sdk.Coin{}, + expectReverseCharge: true, + }, + } + + for _, c := range cases { + s.Run(c.name, func() { + s.SetupTest(true) // setup + s.ctx = s.ctx.WithMinGasPrices(customGasPrices) + + require := s.Require() + tk := s.app.TreasuryKeeper + ak := s.app.AccountKeeper + bk := s.app.BankKeeper + + burnTaxRate := sdk.NewDecWithPrec(5, 3) + burnSplitRate := sdk.NewDecWithPrec(5, 1) + oracleSplitRate := sdk.ZeroDec() + + // Set burn split rate to 50% + tk.SetBurnSplitRate(s.ctx, burnSplitRate) + tk.SetOracleSplitRate(s.ctx, oracleSplitRate) + + s.txBuilder = s.clientCtx.TxConfig.NewTxBuilder() + + tk.AddBurnTaxExemptionAddress(s.ctx, addrs[0].String()) + tk.AddBurnTaxExemptionAddress(s.ctx, addrs[1].String()) + + mfd := ante.NewFeeDecorator(s.app.AccountKeeper, s.app.BankKeeper, s.app.FeeGrantKeeper, s.app.TreasuryKeeper, s.app.DistrKeeper, s.app.TaxKeeper) + antehandler := sdk.ChainAnteDecorators(mfd) + pd := post.NewTaxDecorator(s.app.TaxKeeper, bk, ak, tk) + posthandler := sdk.ChainPostDecorators(pd) + + // Fund accounts with both denoms + for i := 0; i < 4; i++ { + coins := sdk.NewCoins( + sdk.NewCoin(denom1, sdk.NewInt(10000000)), + sdk.NewCoin(denom2, sdk.NewInt(10000000)), + ) + testutil.FundAccount(s.app.BankKeeper, s.ctx, addrs[i], coins) + } + + // Set up transaction with multiple fee denoms + feeAmount := sdk.NewCoins(c.minFeeAmounts...) + gasLimit := testdata.NewTestGasLimit() + require.NoError(s.txBuilder.SetMsgs(c.msgCreator()...)) + s.txBuilder.SetFeeAmount(feeAmount) + s.txBuilder.SetGasLimit(gasLimit) + + privs, accNums, accSeqs := []cryptotypes.PrivKey{c.msgSigner}, []uint64{0}, []uint64{0} + tx, err := s.CreateTestTx(privs, accNums, accSeqs, s.ctx.ChainID()) + require.NoError(err) + + newCtx, err := antehandler(s.ctx, tx, false) + require.NoError(err) + newCtx, err = posthandler(newCtx, tx, false, true) + require.NoError(err) + + actualTaxRate := s.app.TaxKeeper.GetBurnTaxRate(s.ctx) + require.Equal(burnTaxRate, actualTaxRate) + + require.Equal(c.expectReverseCharge, newCtx.Value(taxtypes.ContextKeyTaxReverseCharge)) + + // Check fee collector for each denom + feeCollector := ak.GetModuleAccount(s.ctx, authtypes.FeeCollectorName) + for _, feeCoin := range c.minFeeAmounts { + amountFee := bk.GetBalance(s.ctx, feeCollector.GetAddress(), feeCoin.Denom) + if c.expectReverseCharge { + require.Equal(amountFee, feeCoin) + } else { + expectedFee := sdk.NewCoin( + feeCoin.Denom, + sdk.NewDec(feeCoin.Amount.Int64()).Mul(burnSplitRate).TruncateInt(), + ) + require.Equal(expectedFee, amountFee) + } + } + + // Check tax proceeds + taxProceeds := s.app.TreasuryKeeper.PeekEpochTaxProceeds(s.ctx) + require.Equal(c.expectProceeds, taxProceeds) + }) + } +} + // go test -v -run ^TestAnteTestSuite/TestBurnSplitTax$ github.com/classic-terra/core/v3/custom/auth/ante func (s *AnteTestSuite) TestBurnSplitTax() { s.runBurnSplitTaxTest(sdk.NewDecWithPrec(1, 0), sdk.ZeroDec(), sdk.NewDecWithPrec(5, 1)) // 100% distribute, 0% to oracle From 87758b4ce0be072e7e30952c9d10fca00c3a205f Mon Sep 17 00:00:00 2001 From: Tuan Tran Date: Tue, 26 Nov 2024 10:36:39 +0700 Subject: [PATCH 4/7] update --- tests/e2e/configurer/chain/commands.go | 8 + tests/e2e/e2e_test.go | 310 +++++++++++++------------ 2 files changed, 175 insertions(+), 143 deletions(-) diff --git a/tests/e2e/configurer/chain/commands.go b/tests/e2e/configurer/chain/commands.go index c1e96bac..7cd48d7a 100644 --- a/tests/e2e/configurer/chain/commands.go +++ b/tests/e2e/configurer/chain/commands.go @@ -259,6 +259,14 @@ func (n *NodeConfig) GrantAddress(granter, gratee string, spendLimit string, wal n.LogActionF("successfully granted for address %s", gratee) } +func (n *NodeConfig) GrantBankSend(gratee string, spendLimit string, walletName string) { + n.LogActionF("granting for address %s", gratee) + cmd := []string{"terrad", "tx", "authz", "grant", gratee, "send", fmt.Sprintf("--from=%s", walletName), fmt.Sprintf("--spend-limit=%s", spendLimit)} + _, _, err := n.containerManager.ExecTxCmd(n.t, n.chainID, n.Name, cmd) + require.NoError(n.t, err) + n.LogActionF("successfully granted bank send for address %s", gratee) +} + func (n *NodeConfig) CreateWallet(walletName string) string { n.LogActionF("creating wallet %s", walletName) cmd := []string{"terrad", "keys", "add", walletName, "--keyring-backend=test"} diff --git a/tests/e2e/e2e_test.go b/tests/e2e/e2e_test.go index 27fe83e4..0be3621e 100644 --- a/tests/e2e/e2e_test.go +++ b/tests/e2e/e2e_test.go @@ -1,108 +1,104 @@ package e2e import ( - "fmt" - "strconv" - "time" - sdkmath "cosmossdk.io/math" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/classic-terra/core/v3/tests/e2e/initialization" ) -func (s *IntegrationTestSuite) TestIBCWasmHooks() { - if s.skipIBC { - s.T().Skip("Skipping IBC tests") - } - chainA := s.configurer.GetChainConfig(0) - chainB := s.configurer.GetChainConfig(1) - - nodeA, err := chainA.GetDefaultNode() - s.NoError(err) - nodeB, err := chainB.GetDefaultNode() - s.NoError(err) - - nodeA.StoreWasmCode("counter.wasm", initialization.ValidatorWalletName) - chainA.LatestCodeID = int(nodeA.QueryLatestWasmCodeID()) - nodeA.InstantiateWasmContract( - strconv.Itoa(chainA.LatestCodeID), - `{"count": "0"}`, "", - initialization.ValidatorWalletName) - - contracts, err := nodeA.QueryContractsFromID(chainA.LatestCodeID) - s.NoError(err) - s.Len(contracts, 1, "Wrong number of contracts for the counter") - contractAddr := contracts[0] - - transferAmount := sdk.NewInt(10000000) - validatorAddr := nodeB.GetWallet(initialization.ValidatorWalletName) - nodeB.SendIBCTransfer(validatorAddr, contractAddr, fmt.Sprintf("%duluna", transferAmount.Int64()), - fmt.Sprintf(`{"wasm":{"contract":"%s","msg": {"increment": {}} }}`, contractAddr)) - - // check the balance of the contract - s.Eventually(func() bool { - balance, err := nodeA.QueryBalances(contractAddr) - s.Require().NoError(err) - if len(balance) == 0 { - return false - } - return balance[0].Amount.Equal(transferAmount) - }, - initialization.OneMin, - 10*time.Millisecond) - - // sender wasm addr - // senderBech32, err := ibchookskeeper.DeriveIntermediateSender("channel-0", validatorAddr, "terra") - var response interface{} - response, err = nodeA.QueryWasmSmart(contractAddr, `{"get_total_funds": {}}`) - s.Require().NoError(err) - - s.Eventually(func() bool { - response, err = nodeA.QueryWasmSmart(contractAddr, `{"get_total_funds": {}}`) - if err != nil { - return false - } - - totalFunds := response.([]interface{})[0] - amount, err := strconv.ParseInt(totalFunds.(map[string]interface{})["amount"].(string), 10, 64) - if err != nil { - return false - } - denom := totalFunds.(map[string]interface{})["denom"].(string) - - response, err = nodeA.QueryWasmSmart(contractAddr, `{"get_count": {}}`) - if err != nil { - return false - } - count, err := strconv.ParseInt(response.(string), 10, 64) - if err != nil { - return false - } - // check if denom is uluna token ibc - return sdk.NewInt(amount).Equal(transferAmount) && denom == initialization.TerraIBCDenom && count == 1 - }, - 10*time.Second, - 10*time.Millisecond, - ) -} - -func (s *IntegrationTestSuite) TestAddBurnTaxExemptionAddress() { - chain := s.configurer.GetChainConfig(0) - node, err := chain.GetDefaultNode() - s.Require().NoError(err) - - whitelistAddr1 := node.CreateWallet("whitelist1") - whitelistAddr2 := node.CreateWallet("whitelist2") - - chain.AddBurnTaxExemptionAddressProposal(node, whitelistAddr1, whitelistAddr2) - - whitelistedAddresses, err := node.QueryBurnTaxExemptionList() - s.Require().NoError(err) - s.Require().Len(whitelistedAddresses, 2) - s.Require().Contains(whitelistedAddresses, whitelistAddr1) - s.Require().Contains(whitelistedAddresses, whitelistAddr2) -} +// func (s *IntegrationTestSuite) TestIBCWasmHooks() { +// if s.skipIBC { +// s.T().Skip("Skipping IBC tests") +// } +// chainA := s.configurer.GetChainConfig(0) +// chainB := s.configurer.GetChainConfig(1) + +// nodeA, err := chainA.GetDefaultNode() +// s.NoError(err) +// nodeB, err := chainB.GetDefaultNode() +// s.NoError(err) + +// nodeA.StoreWasmCode("counter.wasm", initialization.ValidatorWalletName) +// chainA.LatestCodeID = int(nodeA.QueryLatestWasmCodeID()) +// nodeA.InstantiateWasmContract( +// strconv.Itoa(chainA.LatestCodeID), +// `{"count": "0"}`, "", +// initialization.ValidatorWalletName) + +// contracts, err := nodeA.QueryContractsFromID(chainA.LatestCodeID) +// s.NoError(err) +// s.Len(contracts, 1, "Wrong number of contracts for the counter") +// contractAddr := contracts[0] + +// transferAmount := sdk.NewInt(10000000) +// validatorAddr := nodeB.GetWallet(initialization.ValidatorWalletName) +// nodeB.SendIBCTransfer(validatorAddr, contractAddr, fmt.Sprintf("%duluna", transferAmount.Int64()), +// fmt.Sprintf(`{"wasm":{"contract":"%s","msg": {"increment": {}} }}`, contractAddr)) + +// // check the balance of the contract +// s.Eventually(func() bool { +// balance, err := nodeA.QueryBalances(contractAddr) +// s.Require().NoError(err) +// if len(balance) == 0 { +// return false +// } +// return balance[0].Amount.Equal(transferAmount) +// }, +// initialization.OneMin, +// 10*time.Millisecond) + +// // sender wasm addr +// // senderBech32, err := ibchookskeeper.DeriveIntermediateSender("channel-0", validatorAddr, "terra") +// var response interface{} +// response, err = nodeA.QueryWasmSmart(contractAddr, `{"get_total_funds": {}}`) +// s.Require().NoError(err) + +// s.Eventually(func() bool { +// response, err = nodeA.QueryWasmSmart(contractAddr, `{"get_total_funds": {}}`) +// if err != nil { +// return false +// } + +// totalFunds := response.([]interface{})[0] +// amount, err := strconv.ParseInt(totalFunds.(map[string]interface{})["amount"].(string), 10, 64) +// if err != nil { +// return false +// } +// denom := totalFunds.(map[string]interface{})["denom"].(string) + +// response, err = nodeA.QueryWasmSmart(contractAddr, `{"get_count": {}}`) +// if err != nil { +// return false +// } +// count, err := strconv.ParseInt(response.(string), 10, 64) +// if err != nil { +// return false +// } +// // check if denom is uluna token ibc +// return sdk.NewInt(amount).Equal(transferAmount) && denom == initialization.TerraIBCDenom && count == 1 +// }, +// 10*time.Second, +// 10*time.Millisecond, +// ) +// } + +// func (s *IntegrationTestSuite) TestAddBurnTaxExemptionAddress() { +// chain := s.configurer.GetChainConfig(0) +// node, err := chain.GetDefaultNode() +// s.Require().NoError(err) + +// whitelistAddr1 := node.CreateWallet("whitelist1") +// whitelistAddr2 := node.CreateWallet("whitelist2") + +// chain.AddBurnTaxExemptionAddressProposal(node, whitelistAddr1, whitelistAddr2) + +// whitelistedAddresses, err := node.QueryBurnTaxExemptionList() +// s.Require().NoError(err) +// s.Require().Len(whitelistedAddresses, 2) +// s.Require().Contains(whitelistedAddresses, whitelistAddr1) +// s.Require().Contains(whitelistedAddresses, whitelistAddr2) +// } func (s *IntegrationTestSuite) TestFeeTax() { chain := s.configurer.GetChainConfig(0) @@ -176,63 +172,91 @@ func (s *IntegrationTestSuite) TestFeeTax() { s.Require().Equal(newValidatorBalance, validatorBalance.Sub(sdk.NewCoin(initialization.TerraDenom, subAmount))) } -func (s *IntegrationTestSuite) TestFeeTaxWasm() { +func (s *IntegrationTestSuite) TestAuthz() { chain := s.configurer.GetChainConfig(0) node, err := chain.GetDefaultNode() s.Require().NoError(err) - testAddr := node.CreateWallet("test") - transferAmount := sdkmath.NewInt(100000000) - transferCoin := sdk.NewCoin(initialization.TerraDenom, transferAmount) - node.BankSend(fmt.Sprintf("%suluna", transferAmount.Mul(sdk.NewInt(4))), initialization.ValidatorWalletName, testAddr) - node.StoreWasmCode("counter.wasm", initialization.ValidatorWalletName) - chain.LatestCodeID = int(node.QueryLatestWasmCodeID()) - // instantiate contract and transfer 100000000uluna - node.InstantiateWasmContract( - strconv.Itoa(chain.LatestCodeID), - `{"count": "0"}`, transferCoin.String(), - "test") - - contracts, err := node.QueryContractsFromID(chain.LatestCodeID) - s.Require().NoError(err) - s.Require().Len(contracts, 1, "Wrong number of contracts for the counter") - - balance1, err := node.QuerySpecificBalance(testAddr, initialization.TerraDenom) + transferAmount1 := sdkmath.NewInt(20000000) + transferCoin1 := sdk.NewCoin(initialization.TerraDenom, transferAmount1) + test1Addr := node.CreateWallet("test1") + test2Addr := node.CreateWallet("test2") + validatorAddr := node.GetWallet(initialization.ValidatorWalletName) + s.Require().NotEqual(validatorAddr, "") + validatorBalance, err := node.QuerySpecificBalance(validatorAddr, initialization.TerraDenom) s.Require().NoError(err) - // 400000000 - 100000000 - 100000000 * TaxRate = 300000000 - 10000000 * TaxRate - // taxAmount := initialization.BurnTaxRate.MulInt(transferAmount).TruncateInt() - // s.Require().Equal(balance1.Amount, transferAmount.Mul(sdk.NewInt(3)).Sub(taxAmount)) - // no longer taxed - s.Require().Equal(balance1.Amount, transferAmount.Mul(sdk.NewInt(3))) - - stabilityFee := sdk.NewDecWithPrec(2, 2).MulInt(transferAmount) - node.Instantiate2WasmContract( - strconv.Itoa(chain.LatestCodeID), - `{"count": "0"}`, "salt", - transferCoin.String(), - fmt.Sprintf("%duluna", stabilityFee), "300000", "test") + node.GrantBankSend(test1Addr, transferCoin1.String(), "val") + node.BankSendWithWallet(transferCoin1.String(), validatorAddr, test2Addr, "test1") - contracts, err = node.QueryContractsFromID(chain.LatestCodeID) + newValidatorBalance, err := node.QuerySpecificBalance(validatorAddr, initialization.TerraDenom) s.Require().NoError(err) - s.Require().Len(contracts, 2, "Wrong number of contracts for the counter") - balance2, err := node.QuerySpecificBalance(testAddr, initialization.TerraDenom) + balanceTest2, err := node.QuerySpecificBalance(test2Addr, initialization.TerraDenom) s.Require().NoError(err) - // balance1 - 100000000 - 100000000 * TaxRate - // taxAmount = initialization.BurnTaxRate.MulInt(transferAmount).TruncateInt() - // s.Require().Equal(balance2.Amount, balance1.Amount.Sub(transferAmount).Sub(taxAmount)) - // no longer taxed - s.Require().Equal(balance2.Amount, balance1.Amount.Sub(transferAmount)) - contractAddr := contracts[0] - node.WasmExecute(contractAddr, `{"donate": {}}`, transferCoin.String(), fmt.Sprintf("%duluna", stabilityFee), "test") + s.Require().Equal(transferAmount1.Sub(initialization.BurnTaxRate.MulInt(transferAmount1).TruncateInt()), balanceTest2.Amount) + s.Require().Equal(validatorBalance.Amount.Sub(transferAmount1), newValidatorBalance.Amount) - balance3, err := node.QuerySpecificBalance(testAddr, initialization.TerraDenom) - s.Require().NoError(err) - // balance2 - 100000000 - 100000000 * TaxRate - // taxAmount = initialization.BurnTaxRate.MulInt(transferAmount).TruncateInt() - // s.Require().Equal(balance3.Amount, balance2.Amount.Sub(transferAmount).Sub(taxAmount)) - // no longer taxed - s.Require().Equal(balance3.Amount, balance2.Amount.Sub(transferAmount)) } + +// func (s *IntegrationTestSuite) TestFeeTaxWasm() { +// chain := s.configurer.GetChainConfig(0) +// node, err := chain.GetDefaultNode() +// s.Require().NoError(err) + +// testAddr := node.CreateWallet("test") +// transferAmount := sdkmath.NewInt(100000000) +// transferCoin := sdk.NewCoin(initialization.TerraDenom, transferAmount) +// node.BankSend(fmt.Sprintf("%suluna", transferAmount.Mul(sdk.NewInt(4))), initialization.ValidatorWalletName, testAddr) +// node.StoreWasmCode("counter.wasm", initialization.ValidatorWalletName) +// chain.LatestCodeID = int(node.QueryLatestWasmCodeID()) +// // instantiate contract and transfer 100000000uluna +// node.InstantiateWasmContract( +// strconv.Itoa(chain.LatestCodeID), +// `{"count": "0"}`, transferCoin.String(), +// "test") + +// contracts, err := node.QueryContractsFromID(chain.LatestCodeID) +// s.Require().NoError(err) +// s.Require().Len(contracts, 1, "Wrong number of contracts for the counter") + +// balance1, err := node.QuerySpecificBalance(testAddr, initialization.TerraDenom) +// s.Require().NoError(err) +// // 400000000 - 100000000 - 100000000 * TaxRate = 300000000 - 10000000 * TaxRate +// // taxAmount := initialization.BurnTaxRate.MulInt(transferAmount).TruncateInt() +// // s.Require().Equal(balance1.Amount, transferAmount.Mul(sdk.NewInt(3)).Sub(taxAmount)) +// // no longer taxed +// s.Require().Equal(balance1.Amount, transferAmount.Mul(sdk.NewInt(3))) + +// stabilityFee := sdk.NewDecWithPrec(2, 2).MulInt(transferAmount) + +// node.Instantiate2WasmContract( +// strconv.Itoa(chain.LatestCodeID), +// `{"count": "0"}`, "salt", +// transferCoin.String(), +// fmt.Sprintf("%duluna", stabilityFee), "300000", "test") + +// contracts, err = node.QueryContractsFromID(chain.LatestCodeID) +// s.Require().NoError(err) +// s.Require().Len(contracts, 2, "Wrong number of contracts for the counter") + +// balance2, err := node.QuerySpecificBalance(testAddr, initialization.TerraDenom) +// s.Require().NoError(err) +// // balance1 - 100000000 - 100000000 * TaxRate +// // taxAmount = initialization.BurnTaxRate.MulInt(transferAmount).TruncateInt() +// // s.Require().Equal(balance2.Amount, balance1.Amount.Sub(transferAmount).Sub(taxAmount)) +// // no longer taxed +// s.Require().Equal(balance2.Amount, balance1.Amount.Sub(transferAmount)) + +// contractAddr := contracts[0] +// node.WasmExecute(contractAddr, `{"donate": {}}`, transferCoin.String(), fmt.Sprintf("%duluna", stabilityFee), "test") + +// balance3, err := node.QuerySpecificBalance(testAddr, initialization.TerraDenom) +// s.Require().NoError(err) +// // balance2 - 100000000 - 100000000 * TaxRate +// // taxAmount = initialization.BurnTaxRate.MulInt(transferAmount).TruncateInt() +// // s.Require().Equal(balance3.Amount, balance2.Amount.Sub(transferAmount).Sub(taxAmount)) +// // no longer taxed +// s.Require().Equal(balance3.Amount, balance2.Amount.Sub(transferAmount)) +// } From 0dec28191ab8fe51e29174d0690937c86963ad3e Mon Sep 17 00:00:00 2001 From: Tuan Tran Date: Tue, 26 Nov 2024 17:15:49 +0700 Subject: [PATCH 5/7] add authz e2e --- custom/auth/ante/fee_test.go | 29 ++-- tests/e2e/e2e_test.go | 322 ++++++++++++++++++----------------- 2 files changed, 181 insertions(+), 170 deletions(-) diff --git a/custom/auth/ante/fee_test.go b/custom/auth/ante/fee_test.go index 5cabcf91..c447cbd3 100644 --- a/custom/auth/ante/fee_test.go +++ b/custom/auth/ante/fee_test.go @@ -1067,13 +1067,14 @@ func (s *AnteTestSuite) TestTaxExemptionWithGasPriceEnabled() { denom2Price := sdk.NewDecCoinFromDec(denom2, sdk.NewDecWithPrec(10, 1)) customGasPrices := []sdk.DecCoin{denom1Price, denom2Price} - requiredFees := sdk.NewCoins(sdk.NewInt64Coin(denom2, 200000)) + requiredFees := []sdk.Coin{sdk.NewInt64Coin(denom1, 0), sdk.NewInt64Coin(denom2, 200000)} requiredTaxes := sdk.NewCoins(sdk.NewInt64Coin(denom1, 5000), sdk.NewInt64Coin(denom2, 5000)) cases := []struct { name string msgSigner cryptotypes.PrivKey msgCreator func() []sdk.Msg - minFeeAmounts []sdk.Coin + minFeeAmounts sdk.Coins + taxAmounts sdk.Coins expectProceeds sdk.Coins expectAnteError bool expectReverseCharge bool @@ -1087,10 +1088,8 @@ func (s *AnteTestSuite) TestTaxExemptionWithGasPriceEnabled() { msgs = append(msgs, msg1) return msgs }, - minFeeAmounts: []sdk.Coin{ - sdk.NewInt64Coin(denom1, 0), - sdk.NewInt64Coin(denom2, 0), - }, + minFeeAmounts: sdk.NewCoins(), + taxAmounts: sdk.NewCoins(), expectProceeds: sdk.NewCoins(), expectAnteError: true, expectReverseCharge: false, @@ -1105,6 +1104,7 @@ func (s *AnteTestSuite) TestTaxExemptionWithGasPriceEnabled() { return msgs }, minFeeAmounts: requiredFees, + taxAmounts: []sdk.Coin{sdk.NewInt64Coin(denom1, 0), sdk.NewInt64Coin(denom2, 0)}, expectProceeds: sdk.NewCoins(), expectReverseCharge: true, }, @@ -1117,7 +1117,8 @@ func (s *AnteTestSuite) TestTaxExemptionWithGasPriceEnabled() { msgs = append(msgs, msg1) return msgs }, - minFeeAmounts: requiredFees.Add(requiredTaxes...).Sub(sdk.NewInt64Coin(denom1, 1)), + minFeeAmounts: requiredFees, + taxAmounts: requiredTaxes.Sub(sdk.NewInt64Coin(denom2, 1)), expectProceeds: sdk.NewCoins(), expectReverseCharge: true, }, @@ -1130,7 +1131,8 @@ func (s *AnteTestSuite) TestTaxExemptionWithGasPriceEnabled() { msgs = append(msgs, msg1) return msgs }, - minFeeAmounts: requiredFees.Add(requiredTaxes...), + minFeeAmounts: requiredFees, + taxAmounts: requiredTaxes, expectProceeds: requiredTaxes, expectReverseCharge: false, }, @@ -1174,7 +1176,7 @@ func (s *AnteTestSuite) TestTaxExemptionWithGasPriceEnabled() { } // Set up transaction with multiple fee denoms - feeAmount := sdk.NewCoins(c.minFeeAmounts...) + feeAmount := sdk.NewCoins(c.minFeeAmounts...).Add(c.taxAmounts...) gasLimit := testdata.NewTestGasLimit() require.NoError(s.txBuilder.SetMsgs(c.msgCreator()...)) s.txBuilder.SetFeeAmount(feeAmount) @@ -1201,15 +1203,16 @@ func (s *AnteTestSuite) TestTaxExemptionWithGasPriceEnabled() { // Check fee collector for each denom feeCollector := ak.GetModuleAccount(s.ctx, authtypes.FeeCollectorName) - for _, feeCoin := range c.minFeeAmounts { + for i, feeCoin := range c.minFeeAmounts { + taxCoin := c.taxAmounts[i] amountFee := bk.GetBalance(s.ctx, feeCollector.GetAddress(), feeCoin.Denom) if c.expectReverseCharge { - require.Equal(amountFee, feeCoin) + require.Equal(amountFee, feeCoin.Add(taxCoin)) // tax that isn't paid enough will not be refunded. } else { expectedFee := sdk.NewCoin( feeCoin.Denom, - sdk.NewDec(feeCoin.Amount.Int64()).Mul(burnSplitRate).TruncateInt(), - ) + sdk.NewDec(taxCoin.Amount.Int64()).Mul(burnSplitRate).TruncateInt(), + ).Add(feeCoin) require.Equal(expectedFee, amountFee) } } diff --git a/tests/e2e/e2e_test.go b/tests/e2e/e2e_test.go index 0be3621e..c6d9d27c 100644 --- a/tests/e2e/e2e_test.go +++ b/tests/e2e/e2e_test.go @@ -1,104 +1,108 @@ package e2e import ( + "fmt" + "strconv" + "time" + sdkmath "cosmossdk.io/math" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/classic-terra/core/v3/tests/e2e/initialization" ) -// func (s *IntegrationTestSuite) TestIBCWasmHooks() { -// if s.skipIBC { -// s.T().Skip("Skipping IBC tests") -// } -// chainA := s.configurer.GetChainConfig(0) -// chainB := s.configurer.GetChainConfig(1) - -// nodeA, err := chainA.GetDefaultNode() -// s.NoError(err) -// nodeB, err := chainB.GetDefaultNode() -// s.NoError(err) - -// nodeA.StoreWasmCode("counter.wasm", initialization.ValidatorWalletName) -// chainA.LatestCodeID = int(nodeA.QueryLatestWasmCodeID()) -// nodeA.InstantiateWasmContract( -// strconv.Itoa(chainA.LatestCodeID), -// `{"count": "0"}`, "", -// initialization.ValidatorWalletName) - -// contracts, err := nodeA.QueryContractsFromID(chainA.LatestCodeID) -// s.NoError(err) -// s.Len(contracts, 1, "Wrong number of contracts for the counter") -// contractAddr := contracts[0] - -// transferAmount := sdk.NewInt(10000000) -// validatorAddr := nodeB.GetWallet(initialization.ValidatorWalletName) -// nodeB.SendIBCTransfer(validatorAddr, contractAddr, fmt.Sprintf("%duluna", transferAmount.Int64()), -// fmt.Sprintf(`{"wasm":{"contract":"%s","msg": {"increment": {}} }}`, contractAddr)) - -// // check the balance of the contract -// s.Eventually(func() bool { -// balance, err := nodeA.QueryBalances(contractAddr) -// s.Require().NoError(err) -// if len(balance) == 0 { -// return false -// } -// return balance[0].Amount.Equal(transferAmount) -// }, -// initialization.OneMin, -// 10*time.Millisecond) - -// // sender wasm addr -// // senderBech32, err := ibchookskeeper.DeriveIntermediateSender("channel-0", validatorAddr, "terra") -// var response interface{} -// response, err = nodeA.QueryWasmSmart(contractAddr, `{"get_total_funds": {}}`) -// s.Require().NoError(err) - -// s.Eventually(func() bool { -// response, err = nodeA.QueryWasmSmart(contractAddr, `{"get_total_funds": {}}`) -// if err != nil { -// return false -// } - -// totalFunds := response.([]interface{})[0] -// amount, err := strconv.ParseInt(totalFunds.(map[string]interface{})["amount"].(string), 10, 64) -// if err != nil { -// return false -// } -// denom := totalFunds.(map[string]interface{})["denom"].(string) - -// response, err = nodeA.QueryWasmSmart(contractAddr, `{"get_count": {}}`) -// if err != nil { -// return false -// } -// count, err := strconv.ParseInt(response.(string), 10, 64) -// if err != nil { -// return false -// } -// // check if denom is uluna token ibc -// return sdk.NewInt(amount).Equal(transferAmount) && denom == initialization.TerraIBCDenom && count == 1 -// }, -// 10*time.Second, -// 10*time.Millisecond, -// ) -// } - -// func (s *IntegrationTestSuite) TestAddBurnTaxExemptionAddress() { -// chain := s.configurer.GetChainConfig(0) -// node, err := chain.GetDefaultNode() -// s.Require().NoError(err) - -// whitelistAddr1 := node.CreateWallet("whitelist1") -// whitelistAddr2 := node.CreateWallet("whitelist2") - -// chain.AddBurnTaxExemptionAddressProposal(node, whitelistAddr1, whitelistAddr2) - -// whitelistedAddresses, err := node.QueryBurnTaxExemptionList() -// s.Require().NoError(err) -// s.Require().Len(whitelistedAddresses, 2) -// s.Require().Contains(whitelistedAddresses, whitelistAddr1) -// s.Require().Contains(whitelistedAddresses, whitelistAddr2) -// } +func (s *IntegrationTestSuite) TestIBCWasmHooks() { + if s.skipIBC { + s.T().Skip("Skipping IBC tests") + } + chainA := s.configurer.GetChainConfig(0) + chainB := s.configurer.GetChainConfig(1) + + nodeA, err := chainA.GetDefaultNode() + s.NoError(err) + nodeB, err := chainB.GetDefaultNode() + s.NoError(err) + + nodeA.StoreWasmCode("counter.wasm", initialization.ValidatorWalletName) + chainA.LatestCodeID = int(nodeA.QueryLatestWasmCodeID()) + nodeA.InstantiateWasmContract( + strconv.Itoa(chainA.LatestCodeID), + `{"count": "0"}`, "", + initialization.ValidatorWalletName) + + contracts, err := nodeA.QueryContractsFromID(chainA.LatestCodeID) + s.NoError(err) + s.Len(contracts, 1, "Wrong number of contracts for the counter") + contractAddr := contracts[0] + + transferAmount := sdk.NewInt(10000000) + validatorAddr := nodeB.GetWallet(initialization.ValidatorWalletName) + nodeB.SendIBCTransfer(validatorAddr, contractAddr, fmt.Sprintf("%duluna", transferAmount.Int64()), + fmt.Sprintf(`{"wasm":{"contract":"%s","msg": {"increment": {}} }}`, contractAddr)) + + // check the balance of the contract + s.Eventually(func() bool { + balance, err := nodeA.QueryBalances(contractAddr) + s.Require().NoError(err) + if len(balance) == 0 { + return false + } + return balance[0].Amount.Equal(transferAmount) + }, + initialization.OneMin, + 10*time.Millisecond) + + // sender wasm addr + // senderBech32, err := ibchookskeeper.DeriveIntermediateSender("channel-0", validatorAddr, "terra") + var response interface{} + response, err = nodeA.QueryWasmSmart(contractAddr, `{"get_total_funds": {}}`) + s.Require().NoError(err) + + s.Eventually(func() bool { + response, err = nodeA.QueryWasmSmart(contractAddr, `{"get_total_funds": {}}`) + if err != nil { + return false + } + + totalFunds := response.([]interface{})[0] + amount, err := strconv.ParseInt(totalFunds.(map[string]interface{})["amount"].(string), 10, 64) + if err != nil { + return false + } + denom := totalFunds.(map[string]interface{})["denom"].(string) + + response, err = nodeA.QueryWasmSmart(contractAddr, `{"get_count": {}}`) + if err != nil { + return false + } + count, err := strconv.ParseInt(response.(string), 10, 64) + if err != nil { + return false + } + // check if denom is uluna token ibc + return sdk.NewInt(amount).Equal(transferAmount) && denom == initialization.TerraIBCDenom && count == 1 + }, + 10*time.Second, + 10*time.Millisecond, + ) +} + +func (s *IntegrationTestSuite) TestAddBurnTaxExemptionAddress() { + chain := s.configurer.GetChainConfig(0) + node, err := chain.GetDefaultNode() + s.Require().NoError(err) + + whitelistAddr1 := node.CreateWallet("whitelist1") + whitelistAddr2 := node.CreateWallet("whitelist2") + + chain.AddBurnTaxExemptionAddressProposal(node, whitelistAddr1, whitelistAddr2) + + whitelistedAddresses, err := node.QueryBurnTaxExemptionList() + s.Require().NoError(err) + s.Require().Len(whitelistedAddresses, 2) + s.Require().Contains(whitelistedAddresses, whitelistAddr1) + s.Require().Contains(whitelistedAddresses, whitelistAddr2) +} func (s *IntegrationTestSuite) TestFeeTax() { chain := s.configurer.GetChainConfig(0) @@ -115,6 +119,7 @@ func (s *IntegrationTestSuite) TestFeeTax() { s.Require().NoError(err) test1Addr := node.CreateWallet("test1") + s.Require().NotEqual(test1Addr, "") // Test 1: banktypes.MsgSend // burn tax with bank send @@ -134,6 +139,7 @@ func (s *IntegrationTestSuite) TestFeeTax() { // Test 2: try bank send with grant test2Addr := node.CreateWallet("test2") + s.Require().NotEqual(test2Addr, "") transferAmount2 := sdkmath.NewInt(10000000) transferCoin2 := sdk.NewCoin(initialization.TerraDenom, transferAmount2) @@ -179,15 +185,17 @@ func (s *IntegrationTestSuite) TestAuthz() { transferAmount1 := sdkmath.NewInt(20000000) transferCoin1 := sdk.NewCoin(initialization.TerraDenom, transferAmount1) - test1Addr := node.CreateWallet("test1") - test2Addr := node.CreateWallet("test2") + test1WalletName := "authz1" + test2WalletName := "authz2" + test1Addr := node.CreateWallet(test1WalletName) + test2Addr := node.CreateWallet(test2WalletName) validatorAddr := node.GetWallet(initialization.ValidatorWalletName) s.Require().NotEqual(validatorAddr, "") validatorBalance, err := node.QuerySpecificBalance(validatorAddr, initialization.TerraDenom) s.Require().NoError(err) node.GrantBankSend(test1Addr, transferCoin1.String(), "val") - node.BankSendWithWallet(transferCoin1.String(), validatorAddr, test2Addr, "test1") + node.BankSendWithWallet(transferCoin1.String(), validatorAddr, test2Addr, test1WalletName) newValidatorBalance, err := node.QuerySpecificBalance(validatorAddr, initialization.TerraDenom) s.Require().NoError(err) @@ -195,68 +203,68 @@ func (s *IntegrationTestSuite) TestAuthz() { balanceTest2, err := node.QuerySpecificBalance(test2Addr, initialization.TerraDenom) s.Require().NoError(err) - s.Require().Equal(transferAmount1.Sub(initialization.BurnTaxRate.MulInt(transferAmount1).TruncateInt()), balanceTest2.Amount) - s.Require().Equal(validatorBalance.Amount.Sub(transferAmount1), newValidatorBalance.Amount) + s.Require().Equal(transferAmount1, balanceTest2.Amount) + s.Require().Equal(validatorBalance.Amount.Sub(transferAmount1).Sub(initialization.BurnTaxRate.MulInt(transferAmount1).TruncateInt()), newValidatorBalance.Amount) } -// func (s *IntegrationTestSuite) TestFeeTaxWasm() { -// chain := s.configurer.GetChainConfig(0) -// node, err := chain.GetDefaultNode() -// s.Require().NoError(err) - -// testAddr := node.CreateWallet("test") -// transferAmount := sdkmath.NewInt(100000000) -// transferCoin := sdk.NewCoin(initialization.TerraDenom, transferAmount) -// node.BankSend(fmt.Sprintf("%suluna", transferAmount.Mul(sdk.NewInt(4))), initialization.ValidatorWalletName, testAddr) -// node.StoreWasmCode("counter.wasm", initialization.ValidatorWalletName) -// chain.LatestCodeID = int(node.QueryLatestWasmCodeID()) -// // instantiate contract and transfer 100000000uluna -// node.InstantiateWasmContract( -// strconv.Itoa(chain.LatestCodeID), -// `{"count": "0"}`, transferCoin.String(), -// "test") - -// contracts, err := node.QueryContractsFromID(chain.LatestCodeID) -// s.Require().NoError(err) -// s.Require().Len(contracts, 1, "Wrong number of contracts for the counter") - -// balance1, err := node.QuerySpecificBalance(testAddr, initialization.TerraDenom) -// s.Require().NoError(err) -// // 400000000 - 100000000 - 100000000 * TaxRate = 300000000 - 10000000 * TaxRate -// // taxAmount := initialization.BurnTaxRate.MulInt(transferAmount).TruncateInt() -// // s.Require().Equal(balance1.Amount, transferAmount.Mul(sdk.NewInt(3)).Sub(taxAmount)) -// // no longer taxed -// s.Require().Equal(balance1.Amount, transferAmount.Mul(sdk.NewInt(3))) - -// stabilityFee := sdk.NewDecWithPrec(2, 2).MulInt(transferAmount) - -// node.Instantiate2WasmContract( -// strconv.Itoa(chain.LatestCodeID), -// `{"count": "0"}`, "salt", -// transferCoin.String(), -// fmt.Sprintf("%duluna", stabilityFee), "300000", "test") - -// contracts, err = node.QueryContractsFromID(chain.LatestCodeID) -// s.Require().NoError(err) -// s.Require().Len(contracts, 2, "Wrong number of contracts for the counter") - -// balance2, err := node.QuerySpecificBalance(testAddr, initialization.TerraDenom) -// s.Require().NoError(err) -// // balance1 - 100000000 - 100000000 * TaxRate -// // taxAmount = initialization.BurnTaxRate.MulInt(transferAmount).TruncateInt() -// // s.Require().Equal(balance2.Amount, balance1.Amount.Sub(transferAmount).Sub(taxAmount)) -// // no longer taxed -// s.Require().Equal(balance2.Amount, balance1.Amount.Sub(transferAmount)) - -// contractAddr := contracts[0] -// node.WasmExecute(contractAddr, `{"donate": {}}`, transferCoin.String(), fmt.Sprintf("%duluna", stabilityFee), "test") - -// balance3, err := node.QuerySpecificBalance(testAddr, initialization.TerraDenom) -// s.Require().NoError(err) -// // balance2 - 100000000 - 100000000 * TaxRate -// // taxAmount = initialization.BurnTaxRate.MulInt(transferAmount).TruncateInt() -// // s.Require().Equal(balance3.Amount, balance2.Amount.Sub(transferAmount).Sub(taxAmount)) -// // no longer taxed -// s.Require().Equal(balance3.Amount, balance2.Amount.Sub(transferAmount)) -// } +func (s *IntegrationTestSuite) TestFeeTaxWasm() { + chain := s.configurer.GetChainConfig(0) + node, err := chain.GetDefaultNode() + s.Require().NoError(err) + + testAddr := node.CreateWallet("test") + transferAmount := sdkmath.NewInt(100000000) + transferCoin := sdk.NewCoin(initialization.TerraDenom, transferAmount) + node.BankSend(fmt.Sprintf("%suluna", transferAmount.Mul(sdk.NewInt(4))), initialization.ValidatorWalletName, testAddr) + node.StoreWasmCode("counter.wasm", initialization.ValidatorWalletName) + chain.LatestCodeID = int(node.QueryLatestWasmCodeID()) + // instantiate contract and transfer 100000000uluna + node.InstantiateWasmContract( + strconv.Itoa(chain.LatestCodeID), + `{"count": "0"}`, transferCoin.String(), + "test") + + contracts, err := node.QueryContractsFromID(chain.LatestCodeID) + s.Require().NoError(err) + s.Require().Len(contracts, 1, "Wrong number of contracts for the counter") + + balance1, err := node.QuerySpecificBalance(testAddr, initialization.TerraDenom) + s.Require().NoError(err) + // 400000000 - 100000000 - 100000000 * TaxRate = 300000000 - 10000000 * TaxRate + // taxAmount := initialization.BurnTaxRate.MulInt(transferAmount).TruncateInt() + // s.Require().Equal(balance1.Amount, transferAmount.Mul(sdk.NewInt(3)).Sub(taxAmount)) + // no longer taxed + s.Require().Equal(balance1.Amount, transferAmount.Mul(sdk.NewInt(3))) + + stabilityFee := sdk.NewDecWithPrec(2, 2).MulInt(transferAmount) + + node.Instantiate2WasmContract( + strconv.Itoa(chain.LatestCodeID), + `{"count": "0"}`, "salt", + transferCoin.String(), + fmt.Sprintf("%duluna", stabilityFee), "300000", "test") + + contracts, err = node.QueryContractsFromID(chain.LatestCodeID) + s.Require().NoError(err) + s.Require().Len(contracts, 2, "Wrong number of contracts for the counter") + + balance2, err := node.QuerySpecificBalance(testAddr, initialization.TerraDenom) + s.Require().NoError(err) + // balance1 - 100000000 - 100000000 * TaxRate + // taxAmount = initialization.BurnTaxRate.MulInt(transferAmount).TruncateInt() + // s.Require().Equal(balance2.Amount, balance1.Amount.Sub(transferAmount).Sub(taxAmount)) + // no longer taxed + s.Require().Equal(balance2.Amount, balance1.Amount.Sub(transferAmount)) + + contractAddr := contracts[0] + node.WasmExecute(contractAddr, `{"donate": {}}`, transferCoin.String(), fmt.Sprintf("%duluna", stabilityFee), "test") + + balance3, err := node.QuerySpecificBalance(testAddr, initialization.TerraDenom) + s.Require().NoError(err) + // balance2 - 100000000 - 100000000 * TaxRate + // taxAmount = initialization.BurnTaxRate.MulInt(transferAmount).TruncateInt() + // s.Require().Equal(balance3.Amount, balance2.Amount.Sub(transferAmount).Sub(taxAmount)) + // no longer taxed + s.Require().Equal(balance3.Amount, balance2.Amount.Sub(transferAmount)) +} From f16ec9f0f18587a7172e95edaa949ee9544c9768 Mon Sep 17 00:00:00 2001 From: Tuan Tran Date: Wed, 27 Nov 2024 18:28:02 +0700 Subject: [PATCH 6/7] lint --- custom/auth/ante/fee_test.go | 18 +- custom/auth/ante/integration_test.go | 242 --------------------------- tests/e2e/e2e_test.go | 1 - 3 files changed, 10 insertions(+), 251 deletions(-) delete mode 100644 custom/auth/ante/integration_test.go diff --git a/custom/auth/ante/fee_test.go b/custom/auth/ante/fee_test.go index c447cbd3..e6602a6a 100644 --- a/custom/auth/ante/fee_test.go +++ b/custom/auth/ante/fee_test.go @@ -557,7 +557,8 @@ func (s *AnteTestSuite) TestTaxExemption() { minFeeAmount: 0, expectProceeds: 0, expectReverseCharge: false, - }, { + }, + { name: "MsgSend(normal -> normal)", msgSigner: privs[2], msgCreator: func() []sdk.Msg { @@ -588,7 +589,8 @@ func (s *AnteTestSuite) TestTaxExemption() { minFeeAmount: feeAmt / 2, expectProceeds: 0, expectReverseCharge: true, - }, { + }, + { name: "MsgSend(normal -> normal, reverse charge)", msgSigner: privs[2], msgCreator: func() []sdk.Msg { @@ -603,7 +605,8 @@ func (s *AnteTestSuite) TestTaxExemption() { minFeeAmount: 1000, expectProceeds: 0, expectReverseCharge: true, - }, { + }, + { name: "MsgExec(MsgSend(normal -> normal))", msgSigner: privs[2], msgCreator: func() []sdk.Msg { @@ -652,7 +655,8 @@ func (s *AnteTestSuite) TestTaxExemption() { minFeeAmount: feeAmt, expectProceeds: feeAmt, expectReverseCharge: false, - }, { + }, + { name: "MsgSend(exemption -> exemption), MsgMultiSend(exemption -> normal, exemption -> exemption)", msgSigner: privs[0], msgCreator: func() []sdk.Msg { @@ -689,7 +693,8 @@ func (s *AnteTestSuite) TestTaxExemption() { minFeeAmount: feeAmt * 2, expectProceeds: feeAmt * 2, expectReverseCharge: false, - }, { + }, + { name: "MsgExecuteContract(exemption), MsgExecuteContract(normal)", msgSigner: privs[3], msgCreator: func() []sdk.Msg { @@ -791,7 +796,6 @@ func (s *AnteTestSuite) TestTaxExemption() { // there should be no coin in burn module // run once with reverse charge and once without for _, c := range cases { - s.Run(c.name, func() { s.SetupTest(true) // setup require := s.Require() @@ -857,9 +861,7 @@ func (s *AnteTestSuite) TestTaxExemption() { taxProceeds := s.app.TreasuryKeeper.PeekEpochTaxProceeds(s.ctx) require.Equal(sdk.NewCoins(sdk.NewCoin(core.MicroSDRDenom, sdk.NewInt(c.expectProceeds))), taxProceeds) }) - } - } func (s *AnteTestSuite) TestTaxExemptionWithMultipleDenoms() { diff --git a/custom/auth/ante/integration_test.go b/custom/auth/ante/integration_test.go deleted file mode 100644 index 3b4edec8..00000000 --- a/custom/auth/ante/integration_test.go +++ /dev/null @@ -1,242 +0,0 @@ -package ante_test - -import ( - cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" - "github.com/cosmos/cosmos-sdk/testutil/testdata" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/auth/ante" - "github.com/cosmos/cosmos-sdk/x/auth/types" - "github.com/cosmos/cosmos-sdk/x/bank/testutil" - banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" - - wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types" - - customante "github.com/classic-terra/core/v3/custom/auth/ante" - core "github.com/classic-terra/core/v3/types" - taxtypes "github.com/classic-terra/core/v3/x/tax/types" - treasurytypes "github.com/classic-terra/core/v3/x/treasury/types" -) - -// go test -v -run ^TestAnteTestSuite/TestIntegrationTaxExemption$ github.com/classic-terra/core/v3/custom/auth/ante -func (s *AnteTestSuite) TestIntegrationTaxExemption() { - // keys and addresses - var privs []cryptotypes.PrivKey - var addrs []sdk.AccAddress - - // 0, 1: exemption - // 2, 3: normal - for i := 0; i < 4; i++ { - priv, _, addr := testdata.KeyTestPubAddr() - privs = append(privs, priv) - addrs = append(addrs, addr) - - } - - // set send amount - sendAmt := int64(1_000_000) - sendCoin := sdk.NewInt64Coin(core.MicroSDRDenom, sendAmt) - feeAmt := int64(5000) - - cases := []struct { - name string - msgSigner int64 - msgCreator func() []sdk.Msg - expectedFeeAmount int64 - expectedReverseCharge bool - }{ - { - name: "MsgSend(exemption -> exemption)", - msgSigner: 0, - msgCreator: func() []sdk.Msg { - var msgs []sdk.Msg - - msg1 := banktypes.NewMsgSend(addrs[0], addrs[1], sdk.NewCoins(sendCoin)) - msgs = append(msgs, msg1) - - return msgs - }, - expectedFeeAmount: 0, - expectedReverseCharge: false, - }, { - name: "MsgSend(normal -> normal)", - msgSigner: 2, - msgCreator: func() []sdk.Msg { - var msgs []sdk.Msg - - msg1 := banktypes.NewMsgSend(addrs[2], addrs[3], sdk.NewCoins(sendCoin)) - msgs = append(msgs, msg1) - - return msgs - }, - // tax this one hence burn amount is fee amount - expectedFeeAmount: feeAmt, - expectedReverseCharge: false, - }, { - name: "MsgSend(exemption -> normal), MsgSend(exemption -> exemption)", - msgSigner: 0, - msgCreator: func() []sdk.Msg { - var msgs []sdk.Msg - - msg1 := banktypes.NewMsgSend(addrs[0], addrs[2], sdk.NewCoins(sendCoin)) - msgs = append(msgs, msg1) - msg2 := banktypes.NewMsgSend(addrs[0], addrs[1], sdk.NewCoins(sendCoin)) - msgs = append(msgs, msg2) - - return msgs - }, - // tax this one hence burn amount is fee amount - expectedFeeAmount: feeAmt, - expectedReverseCharge: true, - }, { - name: "MsgSend(exemption -> exemption), MsgMultiSend(exemption -> normal, exemption)", - msgSigner: 0, - msgCreator: func() []sdk.Msg { - var msgs []sdk.Msg - - msg1 := banktypes.NewMsgSend(addrs[0], addrs[1], sdk.NewCoins(sendCoin)) - msgs = append(msgs, msg1) - msg2 := banktypes.NewMsgMultiSend( - []banktypes.Input{ - { - Address: addrs[0].String(), - Coins: sdk.NewCoins(sendCoin.Add(sendCoin)), - }, - }, - []banktypes.Output{ - { - Address: addrs[2].String(), - Coins: sdk.NewCoins(sendCoin), - }, - { - Address: addrs[1].String(), - Coins: sdk.NewCoins(sendCoin), - }, - }, - ) - msgs = append(msgs, msg2) - - return msgs - }, - expectedFeeAmount: feeAmt * 2, - expectedReverseCharge: false, - }, - } - - for _, c := range cases { - s.SetupTest(true) // setup - tk := s.app.TreasuryKeeper - ak := s.app.AccountKeeper - bk := s.app.BankKeeper - dk := s.app.DistrKeeper - wk := s.app.WasmKeeper - - // Set burn split rate to 50% - // fee amount should be 500, 50% of 10000 - burnSplitRate := sdk.NewDecWithPrec(5, 1) - tk.SetBurnSplitRate(s.ctx, burnSplitRate) // 50% - - feeCollector := ak.GetModuleAccount(s.ctx, types.FeeCollectorName) - burnModule := ak.GetModuleAccount(s.ctx, treasurytypes.BurnModuleName) - - encodingConfig := s.SetupEncoding() - wasmConfig := wasmtypes.DefaultWasmConfig() - antehandler, err := customante.NewAnteHandler( - customante.HandlerOptions{ - AccountKeeper: ak, - BankKeeper: bk, - WasmKeeper: &wk, - FeegrantKeeper: s.app.FeeGrantKeeper, - OracleKeeper: s.app.OracleKeeper, - TreasuryKeeper: s.app.TreasuryKeeper, - SigGasConsumer: ante.DefaultSigVerificationGasConsumer, - SignModeHandler: encodingConfig.TxConfig.SignModeHandler(), - IBCKeeper: *s.app.IBCKeeper, - DistributionKeeper: dk, - WasmConfig: &wasmConfig, - TXCounterStoreKey: s.app.GetKey(wasmtypes.StoreKey), - TaxKeeper: &s.app.TaxKeeper, - }, - ) - s.Require().NoError(err) - - for i := 0; i < 4; i++ { - coins := sdk.NewCoins(sdk.NewInt64Coin(core.MicroSDRDenom, 1_000_000)) - testutil.FundAccount(s.app.BankKeeper, s.ctx, addrs[i], coins) - } - - accNums := make([]uint64, len(privs)) - for i, addr := range addrs { - acc := s.app.AccountKeeper.GetAccount(s.ctx, addr) - accNums[i] = acc.GetAccountNumber() - } - - s.txBuilder = s.clientCtx.TxConfig.NewTxBuilder() - - tk.AddBurnTaxExemptionAddress(s.ctx, addrs[0].String()) - tk.AddBurnTaxExemptionAddress(s.ctx, addrs[1].String()) - - s.Run(c.name, func() { - // case 1 provides zero fee so not enough fee - // case 2 provides enough fee - feeCases := []int64{0, feeAmt} - for i := 0; i <= 1; i++ { - feeAmount := sdk.NewCoins(sdk.NewInt64Coin(core.MicroSDRDenom, feeCases[i])) - gasLimit := testdata.NewTestGasLimit() - s.Require().NoError(s.txBuilder.SetMsgs(c.msgCreator()...)) - s.txBuilder.SetFeeAmount(feeAmount) - s.txBuilder.SetGasLimit(gasLimit) - - accNums := make([]uint64, len(privs)) - accSeqs := make([]uint64, len(privs)) - for i, addr := range addrs { - acc := ak.GetAccount(s.ctx, addr) - accNums[i] = acc.GetAccountNumber() - accSeqs[i] = acc.GetSequence() - } - - privs, accNums, accSeqs := []cryptotypes.PrivKey{privs[c.msgSigner]}, []uint64{accNums[c.msgSigner]}, []uint64{accSeqs[c.msgSigner]} - tx, err := s.CreateTestTx(privs, accNums, accSeqs, s.ctx.ChainID()) - s.Require().NoError(err) - - // set zero gas prices - s.ctx = s.ctx.WithMinGasPrices(sdk.NewDecCoins()) - - feeCollectorBefore := bk.GetBalance(s.ctx, feeCollector.GetAddress(), core.MicroSDRDenom) - burnBefore := bk.GetBalance(s.ctx, burnModule.GetAddress(), core.MicroSDRDenom) - communityBefore := dk.GetFeePool(s.ctx).CommunityPool.AmountOf(core.MicroSDRDenom) - supplyBefore := bk.GetSupply(s.ctx, core.MicroSDRDenom) - - newCtx, err := antehandler(s.ctx, tx, false) - if i == 0 && c.expectedFeeAmount != 0 { - /*s.Require().EqualError(err, fmt.Sprintf( - "insufficient fees; got: \"\", required: \"%dusdr\" = \"\"(gas) + \"%dusdr\"(stability): insufficient fee", - c.expectedFeeAmount, c.expectedFeeAmount))*/ - s.Require().NoError(err) - s.Require().Equal(newCtx.Value(taxtypes.ContextKeyTaxReverseCharge), true) // reverse charge due to lack of fee - } else { - s.Require().NoError(err) - } - - feeCollectorAfter := bk.GetBalance(s.ctx, feeCollector.GetAddress(), core.MicroSDRDenom) - burnAfter := bk.GetBalance(s.ctx, burnModule.GetAddress(), core.MicroSDRDenom) - communityAfter := dk.GetFeePool(s.ctx).CommunityPool.AmountOf(core.MicroSDRDenom) - supplyAfter := bk.GetSupply(s.ctx, core.MicroSDRDenom) - - if i == 0 { - s.Require().Equal(feeCollectorBefore, feeCollectorAfter) - s.Require().Equal(burnBefore, burnAfter) - s.Require().Equal(communityBefore, communityAfter) - s.Require().Equal(supplyBefore, supplyAfter) - } - - if i == 1 { - s.Require().Equal(feeCollectorBefore, feeCollectorAfter) - splitAmount := burnSplitRate.MulInt64(c.expectedFeeAmount).TruncateInt() - s.Require().Equal(burnBefore, burnAfter.AddAmount(splitAmount)) - s.Require().Equal(communityBefore, communityAfter.Add(sdk.NewDecFromInt(splitAmount))) - s.Require().Equal(supplyBefore, supplyAfter.SubAmount(splitAmount)) - } - } - }) - } -} diff --git a/tests/e2e/e2e_test.go b/tests/e2e/e2e_test.go index c6d9d27c..7b50d36a 100644 --- a/tests/e2e/e2e_test.go +++ b/tests/e2e/e2e_test.go @@ -205,7 +205,6 @@ func (s *IntegrationTestSuite) TestAuthz() { s.Require().Equal(transferAmount1, balanceTest2.Amount) s.Require().Equal(validatorBalance.Amount.Sub(transferAmount1).Sub(initialization.BurnTaxRate.MulInt(transferAmount1).TruncateInt()), newValidatorBalance.Amount) - } func (s *IntegrationTestSuite) TestFeeTaxWasm() { From a1ab8a9158283d485ed90fb821478e1734d35b67 Mon Sep 17 00:00:00 2001 From: Tuan Tran Date: Wed, 27 Nov 2024 18:30:04 +0700 Subject: [PATCH 7/7] lint --- custom/auth/ante/fee_test.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/custom/auth/ante/fee_test.go b/custom/auth/ante/fee_test.go index e6602a6a..a4c63330 100644 --- a/custom/auth/ante/fee_test.go +++ b/custom/auth/ante/fee_test.go @@ -1192,9 +1192,8 @@ func (s *AnteTestSuite) TestTaxExemptionWithGasPriceEnabled() { if c.expectAnteError { require.Error(err) return - } else { - require.NoError(err) } + require.NoError(err) newCtx, err = posthandler(newCtx, tx, false, true) require.NoError(err)