diff --git a/a.wasm b/a.wasm new file mode 100644 index 000000000..28fed8117 Binary files /dev/null and b/a.wasm differ diff --git a/app/app.go b/app/app.go index 73a944da7..d9da7709c 100644 --- a/app/app.go +++ b/app/app.go @@ -228,6 +228,7 @@ func NewTerraApp( TXCounterStoreKey: app.GetKey(wasmtypes.StoreKey), DyncommKeeper: app.DyncommKeeper, StakingKeeper: app.StakingKeeper, + Tax2Gaskeeper: app.Tax2gasKeeper, Cdc: app.appCodec, }, ) @@ -237,7 +238,11 @@ func NewTerraApp( postHandler, err := custompost.NewPostHandler( custompost.HandlerOptions{ - DyncommKeeper: app.DyncommKeeper, + AccountKeeper: app.AccountKeeper, + BankKeeper: app.BankKeeper, + DyncommKeeper: app.DyncommKeeper, + TreasuryKeeper: app.TreasuryKeeper, + Tax2Gaskeeper: app.Tax2gasKeeper, }, ) if err != nil { diff --git a/app/keepers/keepers.go b/app/keepers/keepers.go index 406fd28c9..829d3b944 100644 --- a/app/keepers/keepers.go +++ b/app/keepers/keepers.go @@ -66,6 +66,8 @@ import ( markettypes "github.com/classic-terra/core/v3/x/market/types" oraclekeeper "github.com/classic-terra/core/v3/x/oracle/keeper" oracletypes "github.com/classic-terra/core/v3/x/oracle/types" + tax2gasKeeper "github.com/classic-terra/core/v3/x/tax2gas/keeper" + tax2gasTypes "github.com/classic-terra/core/v3/x/tax2gas/types" treasurykeeper "github.com/classic-terra/core/v3/x/treasury/keeper" treasurytypes "github.com/classic-terra/core/v3/x/treasury/types" ) @@ -103,10 +105,10 @@ type AppKeepers struct { DyncommKeeper dyncommkeeper.Keeper IBCHooksKeeper *ibchookskeeper.Keeper ConsensusParamsKeeper consensusparamkeeper.Keeper - - Ics20WasmHooks *ibchooks.WasmHooks - IBCHooksWrapper *ibchooks.ICS4Middleware - TransferStack ibctransfer.IBCModule + Tax2gasKeeper tax2gasKeeper.Keeper + Ics20WasmHooks *ibchooks.WasmHooks + IBCHooksWrapper *ibchooks.ICS4Middleware + TransferStack ibctransfer.IBCModule // make scoped keepers public for test purposes ScopedIBCKeeper capabilitykeeper.ScopedKeeper @@ -156,6 +158,7 @@ func NewAppKeepers( treasurytypes.StoreKey, wasmtypes.StoreKey, dyncommtypes.StoreKey, + tax2gasTypes.StoreKey, ) tkeys := sdk.NewTransientStoreKeys(paramstypes.TStoreKey) memKeys := sdk.NewMemoryStoreKeys(capabilitytypes.MemStoreKey) @@ -276,6 +279,12 @@ func NewAppKeepers( stakingtypes.NewMultiStakingHooks(appKeepers.DistrKeeper.Hooks(), appKeepers.SlashingKeeper.Hooks()), ) + appKeepers.Tax2gasKeeper = tax2gasKeeper.NewKeeper( + appCodec, + appKeepers.keys[tax2gasTypes.StoreKey], + appKeepers.GetSubspace(tax2gasTypes.ModuleName), + ) + // Create IBC Keeper appKeepers.IBCKeeper = ibckeeper.NewKeeper( appCodec, @@ -504,6 +513,7 @@ func initParamsKeeper( paramsKeeper.Subspace(treasurytypes.ModuleName) paramsKeeper.Subspace(wasmtypes.ModuleName).WithKeyTable(wasmtypes.ParamKeyTable()) paramsKeeper.Subspace(dyncommtypes.ModuleName) + paramsKeeper.Subspace(tax2gasTypes.ModuleName) return paramsKeeper } diff --git a/app/modules.go b/app/modules.go index a7dfb5cb2..f638fc110 100644 --- a/app/modules.go +++ b/app/modules.go @@ -25,6 +25,8 @@ import ( markettypes "github.com/classic-terra/core/v3/x/market/types" "github.com/classic-terra/core/v3/x/oracle" oracletypes "github.com/classic-terra/core/v3/x/oracle/types" + tax2gas "github.com/classic-terra/core/v3/x/tax2gas" + tax2gasTypes "github.com/classic-terra/core/v3/x/tax2gas/types" "github.com/classic-terra/core/v3/x/treasury" treasuryclient "github.com/classic-terra/core/v3/x/treasury/client" treasurytypes "github.com/classic-terra/core/v3/x/treasury/types" @@ -123,6 +125,7 @@ var ( customwasm.AppModuleBasic{}, ibcfee.AppModuleBasic{}, dyncomm.AppModuleBasic{}, + tax2gas.AppModuleBasic{}, ibchooks.AppModuleBasic{}, consensus.AppModuleBasic{}, ) @@ -184,6 +187,7 @@ func appModules( treasury.NewAppModule(appCodec, app.TreasuryKeeper), wasm.NewAppModule(appCodec, &app.WasmKeeper, app.StakingKeeper, app.AccountKeeper, app.BankKeeper, app.MsgServiceRouter(), app.GetSubspace(wasmtypes.ModuleName)), dyncomm.NewAppModule(appCodec, app.DyncommKeeper, app.StakingKeeper), + tax2gas.NewAppModule(appCodec, app.Tax2gasKeeper), ibchooks.NewAppModule(app.AccountKeeper), consensus.NewAppModule(appCodec, app.ConsensusParamsKeeper), crisis.NewAppModule(app.CrisisKeeper, skipGenesisInvariants, app.GetSubspace(crisistypes.ModuleName)), // always be last to make sure that it checks for all invariants and not only part of them @@ -250,6 +254,7 @@ func orderBeginBlockers() []string { markettypes.ModuleName, wasmtypes.ModuleName, dyncommtypes.ModuleName, + tax2gasTypes.ModuleName, // consensus module consensusparamtypes.ModuleName, } @@ -284,6 +289,7 @@ func orderEndBlockers() []string { markettypes.ModuleName, wasmtypes.ModuleName, dyncommtypes.ModuleName, + tax2gasTypes.ModuleName, // consensus module consensusparamtypes.ModuleName, } @@ -318,6 +324,7 @@ func orderInitGenesis() []string { treasurytypes.ModuleName, wasmtypes.ModuleName, dyncommtypes.ModuleName, + tax2gasTypes.ModuleName, // consensus module consensusparamtypes.ModuleName, } diff --git a/custom/auth/ante/ante.go b/custom/auth/ante/ante.go index b28fbeac6..52610155d 100644 --- a/custom/auth/ante/ante.go +++ b/custom/auth/ante/ante.go @@ -14,6 +14,7 @@ import ( dyncommkeeper "github.com/classic-terra/core/v3/x/dyncomm/keeper" tax2gasante "github.com/classic-terra/core/v3/x/tax2gas/ante" + tax2gasKeeper "github.com/classic-terra/core/v3/x/tax2gas/keeper" "github.com/cosmos/cosmos-sdk/codec" stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" ibcante "github.com/cosmos/ibc-go/v7/modules/core/ante" @@ -42,6 +43,7 @@ type HandlerOptions struct { TXCounterStoreKey storetypes.StoreKey DyncommKeeper dyncommkeeper.Keeper StakingKeeper *stakingkeeper.Keeper + Tax2Gaskeeper tax2gasKeeper.Keeper Cdc codec.BinaryCodec } @@ -90,7 +92,7 @@ func NewAnteHandler(options HandlerOptions) (sdk.AnteHandler, error) { // MinInitialDepositDecorator prevents submitting governance proposal low initial deposit NewMinInitialDepositDecorator(options.GovKeeper, options.TreasuryKeeper), ante.NewConsumeGasForTxSizeDecorator(options.AccountKeeper), - tax2gasante.NewFeeDecorator(options.AccountKeeper, options.BankKeeper, options.FeegrantKeeper, options.TreasuryKeeper), + tax2gasante.NewFeeDecorator(options.AccountKeeper, options.BankKeeper, options.FeegrantKeeper, options.TreasuryKeeper, options.Tax2Gaskeeper), dyncommante.NewDyncommDecorator(options.Cdc, options.DyncommKeeper, options.StakingKeeper), // Do not add any other decorators below this point unless explicitly explain. diff --git a/custom/auth/ante/expected_keeper.go b/custom/auth/ante/expected_keeper.go index 1326fb785..2bb206534 100644 --- a/custom/auth/ante/expected_keeper.go +++ b/custom/auth/ante/expected_keeper.go @@ -29,6 +29,7 @@ type BankKeeper interface { SendCoins(ctx sdk.Context, from, to sdk.AccAddress, amt sdk.Coins) error SendCoinsFromAccountToModule(ctx sdk.Context, senderAddr sdk.AccAddress, recipientModule string, amt sdk.Coins) error SendCoinsFromModuleToModule(ctx sdk.Context, senderModule string, recipientModule string, amt sdk.Coins) error + SendCoinsFromModuleToAccount(ctx sdk.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins) error } type DistrKeeper interface { diff --git a/custom/auth/ante/fee_test.go b/custom/auth/ante/fee_test.go deleted file mode 100644 index 529f89d5f..000000000 --- a/custom/auth/ante/fee_test.go +++ /dev/null @@ -1,940 +0,0 @@ -package ante_test - -import ( - "encoding/json" - "fmt" - "os" - "time" - - 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/types/query" - authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" - authz "github.com/cosmos/cosmos-sdk/x/authz" - "github.com/cosmos/cosmos-sdk/x/bank/testutil" - banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" - stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - - wasmkeeper "github.com/CosmWasm/wasmd/x/wasm/keeper" - wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types" - core "github.com/classic-terra/core/v3/types" - markettypes "github.com/classic-terra/core/v3/x/market/types" - oracletypes "github.com/classic-terra/core/v3/x/oracle/types" - tax2gasante "github.com/classic-terra/core/v3/x/tax2gas/ante" -) - -func (s *AnteTestSuite) TestDeductFeeDecorator_ZeroGas() { - s.SetupTest(true) // setup - s.txBuilder = s.clientCtx.TxConfig.NewTxBuilder() - - mfd := tax2gasante.NewFeeDecorator(s.app.AccountKeeper, s.app.BankKeeper, s.app.FeeGrantKeeper, s.app.TreasuryKeeper) - antehandler := sdk.ChainAnteDecorators(mfd) - - // keys and addresses - priv1, _, addr1 := testdata.KeyTestPubAddr() - coins := sdk.NewCoins(sdk.NewCoin("atom", sdk.NewInt(300))) - testutil.FundAccount(s.app.BankKeeper, s.ctx, addr1, coins) - - // msg and signatures - msg := testdata.NewTestMsg(addr1) - s.Require().NoError(s.txBuilder.SetMsgs(msg)) - - // set zero gas - s.txBuilder.SetGasLimit(0) - - privs, accNums, accSeqs := []cryptotypes.PrivKey{priv1}, []uint64{0}, []uint64{0} - tx, err := s.CreateTestTx(privs, accNums, accSeqs, s.ctx.ChainID()) - s.Require().NoError(err) - - // Set IsCheckTx to true - s.ctx = s.ctx.WithIsCheckTx(true) - - _, err = antehandler(s.ctx, tx, false) - s.Require().Error(err) - - // zero gas is accepted in simulation mode - _, err = antehandler(s.ctx, tx, true) - s.Require().NoError(err) -} - -func (s *AnteTestSuite) TestEnsureMempoolFees() { - s.SetupTest(true) // setup - s.txBuilder = s.clientCtx.TxConfig.NewTxBuilder() - - mfd := tax2gasante.NewFeeDecorator(s.app.AccountKeeper, s.app.BankKeeper, s.app.FeeGrantKeeper, s.app.TreasuryKeeper) - antehandler := sdk.ChainAnteDecorators(mfd) - - // keys and addresses - priv1, _, addr1 := testdata.KeyTestPubAddr() - coins := sdk.NewCoins(sdk.NewCoin("atom", sdk.NewInt(300))) - testutil.FundAccount(s.app.BankKeeper, s.ctx, addr1, coins) - - // msg and signatures - msg := testdata.NewTestMsg(addr1) - feeAmount := testdata.NewTestFeeAmount() - gasLimit := uint64(15) - s.Require().NoError(s.txBuilder.SetMsgs(msg)) - s.txBuilder.SetFeeAmount(feeAmount) - s.txBuilder.SetGasLimit(gasLimit) - - privs, accNums, accSeqs := []cryptotypes.PrivKey{priv1}, []uint64{0}, []uint64{0} - tx, err := s.CreateTestTx(privs, accNums, accSeqs, s.ctx.ChainID()) - s.Require().NoError(err) - - // Set high gas price so standard test fee fails - atomPrice := sdk.NewDecCoinFromDec("atom", sdk.NewDec(20)) - highGasPrice := []sdk.DecCoin{atomPrice} - s.ctx = s.ctx.WithMinGasPrices(highGasPrice) - - // Set IsCheckTx to true - s.ctx = s.ctx.WithIsCheckTx(true) - - // antehandler errors with insufficient fees - _, err = antehandler(s.ctx, tx, false) - s.Require().NotNil(err, "Decorator should have errored on too low fee for local gasPrice") - - // antehandler should not error since we do not check minGasPrice in simulation mode - cacheCtx, _ := s.ctx.CacheContext() - _, err = antehandler(cacheCtx, tx, true) - s.Require().Nil(err, "Decorator should not have errored in simulation mode") - - // Set IsCheckTx to false - s.ctx = s.ctx.WithIsCheckTx(false) - - // antehandler should not error since we do not check minGasPrice in DeliverTx - _, err = antehandler(s.ctx, tx, false) - s.Require().Nil(err, "MempoolFeeDecorator returned error in DeliverTx") - - // Set IsCheckTx back to true for testing sufficient mempool fee - s.ctx = s.ctx.WithIsCheckTx(true) - - atomPrice = sdk.NewDecCoinFromDec("atom", sdk.NewDec(0).Quo(sdk.NewDec(100000))) - lowGasPrice := []sdk.DecCoin{atomPrice} - s.ctx = s.ctx.WithMinGasPrices(lowGasPrice) - - newCtx, err := antehandler(s.ctx, tx, false) - s.Require().Nil(err, "Decorator should not have errored on fee higher than local gasPrice") - // Priority is the smallest gas price amount in any denom. Since we have only 1 gas price - // of 10atom, the priority here is 10. - s.Require().Equal(int64(10), newCtx.Priority()) -} - -func (s *AnteTestSuite) TestDeductFees() { - s.SetupTest(true) // setup - s.txBuilder = s.clientCtx.TxConfig.NewTxBuilder() - - // keys and addresses - priv1, _, addr1 := testdata.KeyTestPubAddr() - - // msg and signatures - msg := testdata.NewTestMsg(addr1) - feeAmount := testdata.NewTestFeeAmount() - gasLimit := testdata.NewTestGasLimit() - s.Require().NoError(s.txBuilder.SetMsgs(msg)) - s.txBuilder.SetFeeAmount(feeAmount) - s.txBuilder.SetGasLimit(gasLimit) - - privs, accNums, accSeqs := []cryptotypes.PrivKey{priv1}, []uint64{0}, []uint64{0} - tx, err := s.CreateTestTx(privs, accNums, accSeqs, s.ctx.ChainID()) - s.Require().NoError(err) - - // Set account with insufficient funds - acc := s.app.AccountKeeper.NewAccountWithAddress(s.ctx, addr1) - s.app.AccountKeeper.SetAccount(s.ctx, acc) - coins := sdk.NewCoins(sdk.NewCoin("atom", sdk.NewInt(10))) - err = testutil.FundAccount(s.app.BankKeeper, s.ctx, addr1, coins) - s.Require().NoError(err) - - dfd := tax2gasante.NewFeeDecorator(s.app.AccountKeeper, s.app.BankKeeper, s.app.FeeGrantKeeper, s.app.TreasuryKeeper) - antehandler := sdk.ChainAnteDecorators(dfd) - - _, err = antehandler(s.ctx, tx, false) - - s.Require().NotNil(err, "Tx did not error when fee payer had insufficient funds") - - // Set account with sufficient funds - s.app.AccountKeeper.SetAccount(s.ctx, acc) - err = testutil.FundAccount(s.app.BankKeeper, s.ctx, addr1, sdk.NewCoins(sdk.NewCoin("atom", sdk.NewInt(200)))) - s.Require().NoError(err) - - _, err = antehandler(s.ctx, tx, false) - - s.Require().Nil(err, "Tx errored after account has been set with sufficient funds") -} - -func (s *AnteTestSuite) TestEnsureMempoolFeesSend() { - s.SetupTest(true) // setup - s.txBuilder = s.clientCtx.TxConfig.NewTxBuilder() - - mfd := tax2gasante.NewFeeDecorator(s.app.AccountKeeper, s.app.BankKeeper, s.app.FeeGrantKeeper, s.app.TreasuryKeeper) - antehandler := sdk.ChainAnteDecorators(mfd) - - // keys and addresses - priv1, _, addr1 := testdata.KeyTestPubAddr() - coins := sdk.NewCoins(sdk.NewCoin(core.MicroSDRDenom, sdk.NewInt(1000000))) - testutil.FundAccount(s.app.BankKeeper, s.ctx, addr1, coins) - - // msg and signatures - sendAmount := int64(1000000) - sendCoins := sdk.NewCoins(sdk.NewInt64Coin(core.MicroSDRDenom, sendAmount)) - msg := banktypes.NewMsgSend(addr1, addr1, sendCoins) - - feeAmount := testdata.NewTestFeeAmount() - gasLimit := testdata.NewTestGasLimit() - s.Require().NoError(s.txBuilder.SetMsgs(msg)) - s.txBuilder.SetFeeAmount(feeAmount) - s.txBuilder.SetGasLimit(gasLimit) - - privs, accNums, accSeqs := []cryptotypes.PrivKey{priv1}, []uint64{0}, []uint64{0} - 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()) - - // Set IsCheckTx to true - s.ctx = s.ctx.WithIsCheckTx(true) - - // antehandler errors with insufficient fees due to tax - _, err = antehandler(s.ctx, tx, false) - s.Require().Error(err, "Decorator should errored on low fee for local gasPrice + tax") - - tk := s.app.TreasuryKeeper - expectedTax := tk.GetTaxRate(s.ctx).MulInt64(sendAmount).TruncateInt() - if taxCap := tk.GetTaxCap(s.ctx, core.MicroSDRDenom); expectedTax.GT(taxCap) { - expectedTax = taxCap - } - - // set tax amount - feeAmount = sdk.NewCoins(sdk.NewCoin(core.MicroSDRDenom, expectedTax)) - s.txBuilder.SetFeeAmount(feeAmount) - tx, err = s.CreateTestTx(privs, accNums, accSeqs, s.ctx.ChainID()) - s.Require().NoError(err) - - // must pass with tax - _, err = antehandler(s.ctx, tx, false) - s.Require().NoError(err, "Decorator should not have errored on fee higher than local gasPrice") -} - -func (s *AnteTestSuite) TestEnsureMempoolFeesSwapSend() { - s.SetupTest(true) // setup - s.txBuilder = s.clientCtx.TxConfig.NewTxBuilder() - - mfd := tax2gasante.NewFeeDecorator(s.app.AccountKeeper, s.app.BankKeeper, s.app.FeeGrantKeeper, s.app.TreasuryKeeper) - antehandler := sdk.ChainAnteDecorators(mfd) - - // keys and addresses - priv1, _, addr1 := testdata.KeyTestPubAddr() - coins := sdk.NewCoins(sdk.NewCoin(core.MicroSDRDenom, sdk.NewInt(1000000))) - testutil.FundAccount(s.app.BankKeeper, s.ctx, addr1, coins) - - // msg and signatures - sendAmount := int64(1000000) - sendCoin := sdk.NewInt64Coin(core.MicroSDRDenom, sendAmount) - msg := markettypes.NewMsgSwapSend(addr1, addr1, sendCoin, core.MicroKRWDenom) - - feeAmount := testdata.NewTestFeeAmount() - gasLimit := testdata.NewTestGasLimit() - s.Require().NoError(s.txBuilder.SetMsgs(msg)) - s.txBuilder.SetFeeAmount(feeAmount) - s.txBuilder.SetGasLimit(gasLimit) - - privs, accNums, accSeqs := []cryptotypes.PrivKey{priv1}, []uint64{0}, []uint64{0} - 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()) - - // Set IsCheckTx to true - s.ctx = s.ctx.WithIsCheckTx(true) - - // antehandler errors with insufficient fees due to tax - _, err = antehandler(s.ctx, tx, false) - s.Require().Error(err, "Decorator should errored on low fee for local gasPrice + tax") - - tk := s.app.TreasuryKeeper - expectedTax := tk.GetTaxRate(s.ctx).MulInt64(sendAmount).TruncateInt() - if taxCap := tk.GetTaxCap(s.ctx, core.MicroSDRDenom); expectedTax.GT(taxCap) { - expectedTax = taxCap - } - - // set tax amount - s.txBuilder.SetFeeAmount(sdk.NewCoins(sdk.NewCoin(core.MicroSDRDenom, expectedTax))) - tx, err = s.CreateTestTx(privs, accNums, accSeqs, s.ctx.ChainID()) - s.Require().NoError(err) - - // must pass with tax - _, err = antehandler(s.ctx, tx, false) - s.Require().NoError(err, "Decorator should not have errored on fee higher than local gasPrice") -} - -func (s *AnteTestSuite) TestEnsureMempoolFeesMultiSend() { - s.SetupTest(true) // setup - s.txBuilder = s.clientCtx.TxConfig.NewTxBuilder() - - mfd := tax2gasante.NewFeeDecorator(s.app.AccountKeeper, s.app.BankKeeper, s.app.FeeGrantKeeper, s.app.TreasuryKeeper) - antehandler := sdk.ChainAnteDecorators(mfd) - - // keys and addresses - priv1, _, addr1 := testdata.KeyTestPubAddr() - coins := sdk.NewCoins(sdk.NewCoin(core.MicroSDRDenom, sdk.NewInt(1000000))) - testutil.FundAccount(s.app.BankKeeper, s.ctx, addr1, coins) - - // msg and signatures - sendAmount := int64(1000000) - sendCoins := sdk.NewCoins(sdk.NewInt64Coin(core.MicroSDRDenom, sendAmount)) - msg := banktypes.NewMsgMultiSend( - []banktypes.Input{ - banktypes.NewInput(addr1, sendCoins), - banktypes.NewInput(addr1, sendCoins), - }, - []banktypes.Output{ - banktypes.NewOutput(addr1, sendCoins), - banktypes.NewOutput(addr1, sendCoins), - }, - ) - - feeAmount := testdata.NewTestFeeAmount() - gasLimit := testdata.NewTestGasLimit() - s.Require().NoError(s.txBuilder.SetMsgs(msg)) - s.txBuilder.SetFeeAmount(feeAmount) - s.txBuilder.SetGasLimit(gasLimit) - - privs, accNums, accSeqs := []cryptotypes.PrivKey{priv1}, []uint64{0}, []uint64{0} - 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()) - - // Set IsCheckTx to true - s.ctx = s.ctx.WithIsCheckTx(true) - - // antehandler errors with insufficient fees due to tax - _, err = antehandler(s.ctx, tx, false) - s.Require().Error(err, "Decorator should errored on low fee for local gasPrice + tax") - - tk := s.app.TreasuryKeeper - expectedTax := tk.GetTaxRate(s.ctx).MulInt64(sendAmount).TruncateInt() - if taxCap := tk.GetTaxCap(s.ctx, core.MicroSDRDenom); expectedTax.GT(taxCap) { - expectedTax = taxCap - } - - // set tax amount - s.txBuilder.SetFeeAmount(sdk.NewCoins(sdk.NewCoin(core.MicroSDRDenom, expectedTax))) - tx, err = s.CreateTestTx(privs, accNums, accSeqs, s.ctx.ChainID()) - s.Require().NoError(err) - _, err = antehandler(s.ctx, tx, false) - s.Require().Error(err, "Decorator should errored on low fee for local gasPrice + tax") - - // must pass with tax - s.txBuilder.SetFeeAmount(sdk.NewCoins(sdk.NewCoin(core.MicroSDRDenom, expectedTax.Add(expectedTax)))) - tx, err = s.CreateTestTx(privs, accNums, accSeqs, s.ctx.ChainID()) - s.Require().NoError(err) - _, err = antehandler(s.ctx, tx, false) - s.Require().NoError(err, "Decorator should not have errored on fee higher than local gasPrice") -} - -func (s *AnteTestSuite) TestEnsureMempoolFeesInstantiateContract() { - s.SetupTest(true) // setup - s.txBuilder = s.clientCtx.TxConfig.NewTxBuilder() - - mfd := tax2gasante.NewFeeDecorator(s.app.AccountKeeper, s.app.BankKeeper, s.app.FeeGrantKeeper, s.app.TreasuryKeeper) - antehandler := sdk.ChainAnteDecorators(mfd) - - // keys and addresses - priv1, _, addr1 := testdata.KeyTestPubAddr() - coins := sdk.NewCoins(sdk.NewCoin(core.MicroSDRDenom, sdk.NewInt(1000000))) - testutil.FundAccount(s.app.BankKeeper, s.ctx, addr1, coins) - - // msg and signatures - sendAmount := int64(1000000) - sendCoins := sdk.NewCoins(sdk.NewInt64Coin(core.MicroSDRDenom, sendAmount)) - msg := &wasmtypes.MsgInstantiateContract{ - Sender: addr1.String(), - Admin: addr1.String(), - CodeID: 0, - Msg: []byte{}, - Funds: sendCoins, - } - - feeAmount := testdata.NewTestFeeAmount() - gasLimit := testdata.NewTestGasLimit() - s.Require().NoError(s.txBuilder.SetMsgs(msg)) - s.txBuilder.SetFeeAmount(feeAmount) - s.txBuilder.SetGasLimit(gasLimit) - - privs, accNums, accSeqs := []cryptotypes.PrivKey{priv1}, []uint64{0}, []uint64{0} - 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()) - - // Set IsCheckTx to true - s.ctx = s.ctx.WithIsCheckTx(true) - - // antehandler errors with insufficient fees due to tax - _, err = antehandler(s.ctx, tx, false) - s.Require().Error(err, "Decorator should errored on low fee for local gasPrice + tax") - - tk := s.app.TreasuryKeeper - expectedTax := tk.GetTaxRate(s.ctx).MulInt64(sendAmount).TruncateInt() - if taxCap := tk.GetTaxCap(s.ctx, core.MicroSDRDenom); expectedTax.GT(taxCap) { - expectedTax = taxCap - } - - // set tax amount - s.txBuilder.SetFeeAmount(sdk.NewCoins(sdk.NewCoin(core.MicroSDRDenom, expectedTax))) - tx, err = s.CreateTestTx(privs, accNums, accSeqs, s.ctx.ChainID()) - s.Require().NoError(err) - - // must pass with tax - _, err = antehandler(s.ctx, tx, false) - s.Require().NoError(err, "Decorator should not have errored on fee higher than local gasPrice") -} - -func (s *AnteTestSuite) TestEnsureMempoolFeesExecuteContract() { - s.SetupTest(true) // setup - s.txBuilder = s.clientCtx.TxConfig.NewTxBuilder() - - mfd := tax2gasante.NewFeeDecorator(s.app.AccountKeeper, s.app.BankKeeper, s.app.FeeGrantKeeper, s.app.TreasuryKeeper) - antehandler := sdk.ChainAnteDecorators(mfd) - - // keys and addresses - priv1, _, addr1 := testdata.KeyTestPubAddr() - coins := sdk.NewCoins(sdk.NewCoin(core.MicroSDRDenom, sdk.NewInt(1000000))) - testutil.FundAccount(s.app.BankKeeper, s.ctx, addr1, coins) - - // msg and signatures - sendAmount := int64(1000000) - sendCoins := sdk.NewCoins(sdk.NewInt64Coin(core.MicroSDRDenom, sendAmount)) - msg := &wasmtypes.MsgExecuteContract{ - Sender: addr1.String(), - Contract: addr1.String(), - Msg: []byte{}, - Funds: sendCoins, - } - - feeAmount := testdata.NewTestFeeAmount() - gasLimit := testdata.NewTestGasLimit() - s.Require().NoError(s.txBuilder.SetMsgs(msg)) - s.txBuilder.SetFeeAmount(feeAmount) - s.txBuilder.SetGasLimit(gasLimit) - - privs, accNums, accSeqs := []cryptotypes.PrivKey{priv1}, []uint64{0}, []uint64{0} - 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()) - - // Set IsCheckTx to true - s.ctx = s.ctx.WithIsCheckTx(true) - - // antehandler errors with insufficient fees due to tax - _, err = antehandler(s.ctx, tx, false) - s.Require().Error(err, "Decorator should errored on low fee for local gasPrice + tax") - - tk := s.app.TreasuryKeeper - expectedTax := tk.GetTaxRate(s.ctx).MulInt64(sendAmount).TruncateInt() - if taxCap := tk.GetTaxCap(s.ctx, core.MicroSDRDenom); expectedTax.GT(taxCap) { - expectedTax = taxCap - } - - // set tax amount - s.txBuilder.SetFeeAmount(sdk.NewCoins(sdk.NewCoin(core.MicroSDRDenom, expectedTax))) - tx, err = s.CreateTestTx(privs, accNums, accSeqs, s.ctx.ChainID()) - s.Require().NoError(err) - - // must pass with tax - _, err = antehandler(s.ctx, tx, false) - s.Require().NoError(err, "Decorator should not have errored on fee higher than local gasPrice") -} - -func (s *AnteTestSuite) TestEnsureMempoolFeesAuthzExec() { - s.SetupTest(true) // setup - s.txBuilder = s.clientCtx.TxConfig.NewTxBuilder() - - mfd := tax2gasante.NewFeeDecorator(s.app.AccountKeeper, s.app.BankKeeper, s.app.FeeGrantKeeper, s.app.TreasuryKeeper) - antehandler := sdk.ChainAnteDecorators(mfd) - - // keys and addresses - priv1, _, addr1 := testdata.KeyTestPubAddr() - coins := sdk.NewCoins(sdk.NewCoin(core.MicroSDRDenom, sdk.NewInt(1000000))) - testutil.FundAccount(s.app.BankKeeper, s.ctx, addr1, coins) - - // msg and signatures - sendAmount := int64(1000000) - sendCoins := sdk.NewCoins(sdk.NewInt64Coin(core.MicroSDRDenom, sendAmount)) - msg := authz.NewMsgExec(addr1, []sdk.Msg{banktypes.NewMsgSend(addr1, addr1, sendCoins)}) - - feeAmount := testdata.NewTestFeeAmount() - gasLimit := testdata.NewTestGasLimit() - s.Require().NoError(s.txBuilder.SetMsgs(&msg)) - s.txBuilder.SetFeeAmount(feeAmount) - s.txBuilder.SetGasLimit(gasLimit) - - privs, accNums, accSeqs := []cryptotypes.PrivKey{priv1}, []uint64{0}, []uint64{0} - 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()) - - // Set IsCheckTx to true - s.ctx = s.ctx.WithIsCheckTx(true) - - // antehandler errors with insufficient fees due to tax - _, err = antehandler(s.ctx, tx, false) - s.Require().Error(err, "Decorator should errored on low fee for local gasPrice + tax") - - tk := s.app.TreasuryKeeper - expectedTax := tk.GetTaxRate(s.ctx).MulInt64(sendAmount).TruncateInt() - if taxCap := tk.GetTaxCap(s.ctx, core.MicroSDRDenom); expectedTax.GT(taxCap) { - expectedTax = taxCap - } - - // set tax amount - s.txBuilder.SetFeeAmount(sdk.NewCoins(sdk.NewCoin(core.MicroSDRDenom, expectedTax))) - tx, err = s.CreateTestTx(privs, accNums, accSeqs, s.ctx.ChainID()) - s.Require().NoError(err) - - // must pass with tax - _, err = antehandler(s.ctx, tx, false) - s.Require().NoError(err, "Decorator should not have errored on fee higher than local gasPrice") -} - -// go test -v -run ^TestAnteTestSuite/TestTaxExemption$ github.com/classic-terra/core/v3/custom/auth/ante -func (s *AnteTestSuite) TestTaxExemption() { - // 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(1000000) - sendCoin := sdk.NewInt64Coin(core.MicroSDRDenom, sendAmt) - feeAmt := int64(1000) - - cases := []struct { - name string - msgSigner cryptotypes.PrivKey - msgCreator func() []sdk.Msg - minFeeAmount int64 - expectProceeds int64 - }{ - { - name: "MsgSend(exemption -> exemption)", - 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 - }, - minFeeAmount: 0, - expectProceeds: 0, - }, { - name: "MsgSend(normal -> normal)", - 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 - }, - // tax this one hence burn amount is fee amount - minFeeAmount: feeAmt, - expectProceeds: feeAmt, - }, { - 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, - }, { - name: "MsgSend(exemption -> normal), MsgSend(exemption -> exemption)", - msgSigner: privs[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 - minFeeAmount: feeAmt, - expectProceeds: feeAmt, - }, { - name: "MsgSend(exemption -> exemption), MsgMultiSend(exemption -> normal, exemption -> exemption)", - 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) - msg2 := banktypes.NewMsgMultiSend( - []banktypes.Input{ - { - Address: addrs[0].String(), - Coins: sdk.NewCoins(sendCoin), - }, - { - Address: addrs[0].String(), - Coins: sdk.NewCoins(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 - }, - minFeeAmount: feeAmt * 2, - expectProceeds: feeAmt * 2, - }, { - 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 set the contract address to tax exemption - addr, _, err := per.Instantiate(s.ctx, CodeID, addrs[0], nil, bz, "my label", nil) - s.Require().NoError(err) - s.app.TreasuryKeeper.AddBurnTaxExemptionAddress(s.ctx, addr.String()) - // instantiate contract then not set to tax exemption - addr1, _, 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 := &wasmtypes.MsgExecuteContract{ - Sender: addrs[3].String(), - Contract: addr1.String(), - Msg: []byte{}, - Funds: sendCoins, - } - msgs = append(msgs, msg2) - return msgs - }, - minFeeAmount: feeAmt, - expectProceeds: feeAmt, - }, - } - - // there should be no coin in burn module - for _, c := range cases { - s.SetupTest(true) // setup - require := s.Require() - tk := s.app.TreasuryKeeper - ak := s.app.AccountKeeper - bk := s.app.BankKeeper - burnSplitRate := sdk.NewDecWithPrec(5, 1) - - // Set burn split rate to 50% - tk.SetBurnSplitRate(s.ctx, burnSplitRate) - - 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 := tax2gasante.NewFeeDecorator(s.app.AccountKeeper, s.app.BankKeeper, s.app.FeeGrantKeeper, s.app.TreasuryKeeper) - antehandler := sdk.ChainAnteDecorators(mfd) - - 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) - - _, err = antehandler(s.ctx, tx, false) - require.NoError(err) - - // check fee collector - feeCollector := ak.GetModuleAccount(s.ctx, authtypes.FeeCollectorName) - amountFee := bk.GetBalance(s.ctx, feeCollector.GetAddress(), core.MicroSDRDenom) - 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)))) - } -} - -// 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)) // 100% - s.runBurnSplitTaxTest(sdk.NewDecWithPrec(1, 1)) // 10% - s.runBurnSplitTaxTest(sdk.NewDecWithPrec(1, 2)) // 0.1% - s.runBurnSplitTaxTest(sdk.NewDecWithPrec(0, 0)) // 0% burn all taxes (old burn tax behavior) - s.runBurnSplitTaxTest(sdk.NewDecWithPrec(-1, 1)) // -10% invalid rate -} - -func (s *AnteTestSuite) runBurnSplitTaxTest(burnSplitRate sdk.Dec) { - s.SetupTest(true) // setup - require := s.Require() - s.txBuilder = s.clientCtx.TxConfig.NewTxBuilder() - - ak := s.app.AccountKeeper - bk := s.app.BankKeeper - tk := s.app.TreasuryKeeper - mfd := tax2gasante.NewFeeDecorator(ak, bk, s.app.FeeGrantKeeper, tk) - antehandler := sdk.ChainAnteDecorators(mfd) - - // Set burn split tax - tk.SetBurnSplitRate(s.ctx, burnSplitRate) - - // keys and addresses - priv1, _, addr1 := testdata.KeyTestPubAddr() - coins := sdk.NewCoins(sdk.NewCoin(core.MicroSDRDenom, sdk.NewInt(1000000))) - testutil.FundAccount(s.app.BankKeeper, s.ctx, addr1, coins) - - // msg and signatures - sendAmount := int64(1000000) - sendCoins := sdk.NewCoins(sdk.NewInt64Coin(core.MicroSDRDenom, sendAmount)) - msg := banktypes.NewMsgSend(addr1, addr1, sendCoins) - - gasLimit := testdata.NewTestGasLimit() - require.NoError(s.txBuilder.SetMsgs(msg)) - s.txBuilder.SetGasLimit(gasLimit) - expectedTax := tk.GetTaxRate(s.ctx).MulInt64(sendAmount).TruncateInt() - if taxCap := tk.GetTaxCap(s.ctx, core.MicroSDRDenom); expectedTax.GT(taxCap) { - expectedTax = taxCap - } - - // set tax amount - s.txBuilder.SetFeeAmount(sdk.NewCoins(sdk.NewCoin(core.MicroSDRDenom, expectedTax))) - - privs, accNums, accSeqs := []cryptotypes.PrivKey{priv1}, []uint64{0}, []uint64{0} - tx, err := s.CreateTestTx(privs, accNums, accSeqs, s.ctx.ChainID()) - require.NoError(err) - - // set zero gas prices - s.ctx = s.ctx.WithMinGasPrices(sdk.NewDecCoins()) - - // Set IsCheckTx to true - s.ctx = s.ctx.WithIsCheckTx(true) - - feeCollector := ak.GetModuleAccount(s.ctx, authtypes.FeeCollectorName) - - amountFeeBefore := bk.GetAllBalances(s.ctx, feeCollector.GetAddress()) - - totalSupplyBefore, _, err := bk.GetPaginatedTotalSupply(s.ctx, &query.PageRequest{}) - require.NoError(err) - fmt.Printf( - "Before: TotalSupply %v, FeeCollector %v\n", - totalSupplyBefore, - amountFeeBefore, - ) - - // send tx to BurnTaxFeeDecorator antehandler - _, err = antehandler(s.ctx, tx, false) - require.NoError(err) - - // burn the burn account - tk.BurnCoinsFromBurnAccount(s.ctx) - - feeCollectorAfter := sdk.NewDecCoinsFromCoins(bk.GetAllBalances(s.ctx, ak.GetModuleAddress(authtypes.FeeCollectorName))...) - taxes := tax2gasante.FilterMsgAndComputeTax(s.ctx, tk, msg) - burnTax := sdk.NewDecCoinsFromCoins(taxes...) - - if burnSplitRate.IsPositive() { - distributionDeltaCoins := burnTax.MulDec(burnSplitRate) - - // expected: community pool 50% - fmt.Printf("BurnSplitRate %v, DistributionDeltaCoins %v\n", burnSplitRate, distributionDeltaCoins) - require.Equal(feeCollectorAfter, distributionDeltaCoins) - burnTax = burnTax.Sub(distributionDeltaCoins) - } - - totalSupplyAfter, _, err := bk.GetPaginatedTotalSupply(s.ctx, &query.PageRequest{}) - require.NoError(err) - if !burnTax.Empty() { - // expected: total supply = tax - split tax - require.Equal( - sdk.NewDecCoinsFromCoins(totalSupplyBefore.Sub(totalSupplyAfter...)...), - burnTax, - ) - } - - fmt.Printf( - "After: TotalSupply %v, FeeCollector %v\n", - totalSupplyAfter, - feeCollectorAfter, - ) -} - -// go test -v -run ^TestAnteTestSuite/TestEnsureIBCUntaxed$ github.com/classic-terra/core/v3/custom/auth/ante -// TestEnsureIBCUntaxed tests that IBC transactions are not taxed, but fee is still deducted -func (s *AnteTestSuite) TestEnsureIBCUntaxed() { - s.SetupTest(true) // setup - s.txBuilder = s.clientCtx.TxConfig.NewTxBuilder() - - mfd := tax2gasante.NewFeeDecorator( - s.app.AccountKeeper, - s.app.BankKeeper, - s.app.FeeGrantKeeper, - s.app.TreasuryKeeper, - ) - antehandler := sdk.ChainAnteDecorators(mfd) - - // keys and addresses - priv1, _, addr1 := testdata.KeyTestPubAddr() - account := s.app.AccountKeeper.NewAccountWithAddress(s.ctx, addr1) - s.app.AccountKeeper.SetAccount(s.ctx, account) - testutil.FundAccount(s.app.BankKeeper, s.ctx, addr1, sdk.NewCoins(sdk.NewInt64Coin(core.MicroSDRDenom, 1_000_000_000))) - - // msg and signatures - sendAmount := int64(1_000_000) - sendCoins := sdk.NewCoins(sdk.NewInt64Coin(core.OsmoIbcDenom, sendAmount)) - msg := banktypes.NewMsgSend(addr1, addr1, sendCoins) - - feeAmount := sdk.NewCoins(sdk.NewInt64Coin(core.MicroSDRDenom, 1_000_000)) - gasLimit := testdata.NewTestGasLimit() - s.Require().NoError(s.txBuilder.SetMsgs(msg)) - s.txBuilder.SetFeeAmount(feeAmount) - s.txBuilder.SetGasLimit(gasLimit) - - privs, accNums, accSeqs := []cryptotypes.PrivKey{priv1}, []uint64{0}, []uint64{0} - 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()) - - // Set IsCheckTx to true - s.ctx = s.ctx.WithIsCheckTx(true) - - // IBC must pass without burn - _, err = antehandler(s.ctx, tx, false) - s.Require().NoError(err, "Decorator should not have errored on IBC denoms") - - // check if tax proceeds are empty - taxProceeds := s.app.TreasuryKeeper.PeekEpochTaxProceeds(s.ctx) - s.Require().True(taxProceeds.Empty()) -} - -// go test -v -run ^TestAnteTestSuite/TestOracleZeroFee$ github.com/classic-terra/core/v3/custom/auth/ante -func (s *AnteTestSuite) TestOracleZeroFee() { - s.SetupTest(true) // setup - s.txBuilder = s.clientCtx.TxConfig.NewTxBuilder() - - mfd := tax2gasante.NewFeeDecorator( - s.app.AccountKeeper, - s.app.BankKeeper, - s.app.FeeGrantKeeper, - s.app.TreasuryKeeper, - ) - antehandler := sdk.ChainAnteDecorators(mfd) - - // keys and addresses - priv1, _, addr1 := testdata.KeyTestPubAddr() - account := s.app.AccountKeeper.NewAccountWithAddress(s.ctx, addr1) - s.app.AccountKeeper.SetAccount(s.ctx, account) - testutil.FundAccount(s.app.BankKeeper, s.ctx, addr1, sdk.NewCoins(sdk.NewInt64Coin(core.MicroSDRDenom, 1_000_000_000))) - - // new val - val, err := stakingtypes.NewValidator(sdk.ValAddress(addr1), priv1.PubKey(), stakingtypes.Description{}) - s.Require().NoError(err) - s.app.StakingKeeper.SetValidator(s.ctx, val) - - // msg and signatures - - // MsgAggregateExchangeRatePrevote - msg := oracletypes.NewMsgAggregateExchangeRatePrevote(oracletypes.GetAggregateVoteHash("salt", "exchange rates", val.GetOperator()), addr1, val.GetOperator()) - s.txBuilder.SetMsgs(msg) - s.txBuilder.SetGasLimit(testdata.NewTestGasLimit()) - s.txBuilder.SetFeeAmount(sdk.NewCoins(sdk.NewInt64Coin(core.MicroSDRDenom, 0))) - privs, accNums, accSeqs := []cryptotypes.PrivKey{priv1}, []uint64{0}, []uint64{0} - tx, err := s.CreateTestTx(privs, accNums, accSeqs, s.ctx.ChainID()) - s.Require().NoError(err) - - _, err = antehandler(s.ctx, tx, false) - s.Require().NoError(err) - - // check fee collector empty - balances := s.app.BankKeeper.GetAllBalances(s.ctx, s.app.AccountKeeper.GetModuleAddress(authtypes.FeeCollectorName)) - s.Require().Equal(sdk.Coins{}, balances) - - // MsgAggregateExchangeRateVote - msg1 := oracletypes.NewMsgAggregateExchangeRateVote("salt", "exchange rates", addr1, val.GetOperator()) - s.txBuilder.SetMsgs(msg1) - tx, err = s.CreateTestTx(privs, accNums, accSeqs, s.ctx.ChainID()) - s.Require().NoError(err) - - _, err = antehandler(s.ctx, tx, false) - s.Require().NoError(err) - - // check fee collector empty - balances = s.app.BankKeeper.GetAllBalances(s.ctx, s.app.AccountKeeper.GetModuleAddress(authtypes.FeeCollectorName)) - s.Require().Equal(sdk.Coins{}, balances) -} diff --git a/custom/auth/post/post.go b/custom/auth/post/post.go index 95f0f1867..0a5fa707b 100644 --- a/custom/auth/post/post.go +++ b/custom/auth/post/post.go @@ -3,12 +3,21 @@ package post import ( dyncommkeeper "github.com/classic-terra/core/v3/x/dyncomm/keeper" dyncommpost "github.com/classic-terra/core/v3/x/dyncomm/post" + tax2gasKeeper "github.com/classic-terra/core/v3/x/tax2gas/keeper" + tax2gasPost "github.com/classic-terra/core/v3/x/tax2gas/post" + "github.com/classic-terra/core/v3/x/tax2gas/types" + tax2gasTypes "github.com/classic-terra/core/v3/x/tax2gas/types" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/auth/ante" ) // HandlerOptions are the options required for constructing a default SDK AnteHandler. type HandlerOptions struct { - DyncommKeeper dyncommkeeper.Keeper + AccountKeeper ante.AccountKeeper + BankKeeper types.BankKeeper + DyncommKeeper dyncommkeeper.Keeper + TreasuryKeeper tax2gasTypes.TreasuryKeeper + Tax2Gaskeeper tax2gasKeeper.Keeper } // NewPostHandler returns an PostHandler that checks and set target @@ -16,5 +25,6 @@ type HandlerOptions struct { func NewPostHandler(options HandlerOptions) (sdk.PostHandler, error) { return sdk.ChainPostDecorators( dyncommpost.NewDyncommPostDecorator(options.DyncommKeeper), + tax2gasPost.NewTax2GasPostDecorator(options.AccountKeeper, options.BankKeeper, options.TreasuryKeeper, options.Tax2Gaskeeper), ), nil } diff --git a/custom/wasm/keeper/handler_plugin.go b/custom/wasm/keeper/handler_plugin.go index 3db8e9a00..b2e8693ce 100644 --- a/custom/wasm/keeper/handler_plugin.go +++ b/custom/wasm/keeper/handler_plugin.go @@ -1,7 +1,13 @@ package keeper import ( - "github.com/classic-terra/core/v3/x/tax2gas/ante" + "fmt" + "regexp" + "strings" + + marketexported "github.com/classic-terra/core/v3/x/market/exported" + oracleexported "github.com/classic-terra/core/v3/x/oracle/exported" + "github.com/classic-terra/core/v3/x/tax2gas/types" treasurykeeper "github.com/classic-terra/core/v3/x/treasury/keeper" wasmvmtypes "github.com/CosmWasm/wasmvm/types" @@ -11,7 +17,9 @@ import ( sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" cosmosante "github.com/cosmos/cosmos-sdk/x/auth/ante" authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper" + authz "github.com/cosmos/cosmos-sdk/x/authz" bankKeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" wasmkeeper "github.com/CosmWasm/wasmd/x/wasm/keeper" wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types" @@ -78,10 +86,13 @@ func (h SDKMessageHandler) DispatchMsg(ctx sdk.Context, contractAddr sdk.AccAddr for _, sdkMsg := range sdkMsgs { // Charge tax on result msg - taxes := ante.FilterMsgAndComputeTax(ctx, h.treasuryKeeper, sdkMsg) + taxes := FilterMsgAndComputeTax(ctx, h.treasuryKeeper, sdkMsg) if !taxes.IsZero() { eventManager := sdk.NewEventManager() contractAcc := h.accountKeeper.GetAccount(ctx, contractAddr) + if err := deductFromMsgs(ctx, h.treasuryKeeper, taxes, sdkMsg); err != nil { + return nil, nil, err + } if err := cosmosante.DeductFees(h.bankKeeper, ctx.WithEventManager(eventManager), contractAcc, taxes); err != nil { return nil, nil, err } @@ -129,3 +140,188 @@ func (h SDKMessageHandler) handleSdkMessage(ctx sdk.Context, contractAddr sdk.Ad // registered within the `msgServiceRouter` already. return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "can't route message %+v", msg) } + +var IBCRegexp = regexp.MustCompile("^ibc/[a-fA-F0-9]{64}$") + +func isIBCDenom(denom string) bool { + return IBCRegexp.MatchString(strings.ToLower(denom)) +} + +// FilterMsgAndComputeTax computes the stability tax on messages. +func FilterMsgAndComputeTax(ctx sdk.Context, tk types.TreasuryKeeper, msgs ...sdk.Msg) sdk.Coins { + taxes := sdk.Coins{} + + for _, msg := range msgs { + switch msg := msg.(type) { + case *banktypes.MsgSend: + if !tk.HasBurnTaxExemptionAddress(ctx, msg.FromAddress, msg.ToAddress) { + taxes = taxes.Add(computeTax(ctx, tk, msg.Amount)...) + } + + case *banktypes.MsgMultiSend: + tainted := 0 + + for _, input := range msg.Inputs { + if tk.HasBurnTaxExemptionAddress(ctx, input.Address) { + tainted++ + } + } + + for _, output := range msg.Outputs { + if tk.HasBurnTaxExemptionAddress(ctx, output.Address) { + tainted++ + } + } + + if tainted != len(msg.Inputs)+len(msg.Outputs) { + for _, input := range msg.Inputs { + taxes = taxes.Add(computeTax(ctx, tk, input.Coins)...) + } + } + + case *marketexported.MsgSwapSend: + taxes = taxes.Add(computeTax(ctx, tk, sdk.NewCoins(msg.OfferCoin))...) + + case *wasmtypes.MsgInstantiateContract: + taxes = taxes.Add(computeTax(ctx, tk, msg.Funds)...) + + case *wasmtypes.MsgInstantiateContract2: + taxes = taxes.Add(computeTax(ctx, tk, msg.Funds)...) + + case *wasmtypes.MsgExecuteContract: + if !tk.HasBurnTaxExemptionContract(ctx, msg.Contract) { + taxes = taxes.Add(computeTax(ctx, tk, msg.Funds)...) + } + + case *authz.MsgExec: + messages, err := msg.GetMessages() + if err == nil { + taxes = taxes.Add(FilterMsgAndComputeTax(ctx, tk, messages...)...) + } + } + } + + return taxes +} + +func deductFromMsgs(ctx sdk.Context, tk types.TreasuryKeeper, taxes sdk.Coins, msgs ...sdk.Msg) (err error) { + for _, msg := range msgs { + switch msg := msg.(type) { + case *banktypes.MsgSend: + if !tk.HasBurnTaxExemptionAddress(ctx, msg.FromAddress, msg.ToAddress) { + msg.Amount = msg.Amount.Sub(taxes...) + fmt.Println("msg.Amount bank send: ", msg.Amount) + } + + case *banktypes.MsgMultiSend: + tainted := 0 + + for _, input := range msg.Inputs { + if tk.HasBurnTaxExemptionAddress(ctx, input.Address) { + tainted++ + } + } + + for _, output := range msg.Outputs { + if tk.HasBurnTaxExemptionAddress(ctx, output.Address) { + tainted++ + } + } + + if tainted != len(msg.Inputs)+len(msg.Outputs) { + for _, input := range msg.Inputs { + input.Coins = input.Coins.Sub(taxes...) + } + } + + case *marketexported.MsgSwapSend: + taxes = taxes.Add(computeTax(ctx, tk, sdk.NewCoins(msg.OfferCoin))...) + if found, taxCoin := taxes.Find(msg.OfferCoin.Denom); found { + if msg.OfferCoin, err = msg.OfferCoin.SafeSub(taxCoin); err != nil { + return sdkerrors.Wrapf(sdkerrors.ErrInsufficientFunds, "insufficient funds to pay tax") + } + } + + case *wasmtypes.MsgInstantiateContract: + var neg bool + if msg.Funds, neg = msg.Funds.SafeSub(taxes...); neg { + return sdkerrors.Wrapf(sdkerrors.ErrInsufficientFunds, "insufficient funds to pay tax") + } + + case *wasmtypes.MsgInstantiateContract2: + var neg bool + if msg.Funds, neg = msg.Funds.SafeSub(taxes...); neg { + return sdkerrors.Wrapf(sdkerrors.ErrInsufficientFunds, "insufficient funds to pay tax") + } + + case *wasmtypes.MsgExecuteContract: + if !tk.HasBurnTaxExemptionContract(ctx, msg.Contract) { + fmt.Println("msg.Funds before: ", msg.Funds) + var neg bool + if msg.Funds, neg = msg.Funds.SafeSub(taxes...); neg { + return sdkerrors.Wrapf(sdkerrors.ErrInsufficientFunds, "insufficient funds to pay tax") + } + fmt.Println("msg.Funds after: ", msg.Funds) + } + + case *authz.MsgExec: + messages, err := msg.GetMessages() + if err == nil { + deductFromMsgs(ctx, tk, taxes, messages...) + } + } + } + + return nil +} + +// computes the stability tax according to tax-rate and tax-cap +func computeTax(ctx sdk.Context, tk types.TreasuryKeeper, principal sdk.Coins) sdk.Coins { + taxRate := tk.GetTaxRate(ctx) + if taxRate.Equal(sdk.ZeroDec()) { + return sdk.Coins{} + } + + taxes := sdk.Coins{} + + for _, coin := range principal { + if coin.Denom == sdk.DefaultBondDenom { + continue + } + + if isIBCDenom(coin.Denom) { + continue + } + + taxDue := sdk.NewDecFromInt(coin.Amount).Mul(taxRate).TruncateInt() + + // If tax due is greater than the tax cap, cap! + taxCap := tk.GetTaxCap(ctx, coin.Denom) + if taxDue.GT(taxCap) { + taxDue = taxCap + } + + if taxDue.Equal(sdk.ZeroInt()) { + continue + } + + taxes = taxes.Add(sdk.NewCoin(coin.Denom, taxDue)) + } + + return taxes +} + +func isOracleTx(msgs []sdk.Msg) bool { + for _, msg := range msgs { + switch msg.(type) { + case *oracleexported.MsgAggregateExchangeRatePrevote: + continue + case *oracleexported.MsgAggregateExchangeRateVote: + continue + default: + return false + } + } + + return true +} diff --git a/deploy.sh b/deploy.sh new file mode 100755 index 000000000..b4d7b4834 --- /dev/null +++ b/deploy.sh @@ -0,0 +1,23 @@ +#!/bin/bash + +terrad tx wasm store forwarder.wasm --from test0 --keyring-backend test --home mytestnet --gas 2000000 -y + +sleep 5 + +terrad tx wasm instantiate 1 {} --label test --no-admin --from test0 --keyring-backend test --home mytestnet -y + +sleep 5 + +contract_address=$(terrad q wasm list-contract-by-code 1 --output json | jq -r '.contracts[0]') + +echo "Contract_addr:" $contract_address + +recipient=$(terrad keys show test1 --keyring-backend test --home mytestnet --output json | jq -r '.address') + +echo "Recipient:" $recipient + +sleep 5 + +terrad tx wasm execute $contract_address '{"forward":{"recipient":"'$recipient'","amount":"100000"}}' --from test0 --keyring-backend test --home mytestnet --amount 100000uluna + +# terra14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9ssrc8au \ No newline at end of file diff --git a/deploy2.sh b/deploy2.sh new file mode 100755 index 000000000..0333665f8 --- /dev/null +++ b/deploy2.sh @@ -0,0 +1,29 @@ +#!/bin/bash + +terrad tx wasm store forwarder4.wasm --from test0 --keyring-backend test --home mytestnet --gas 2000000 -y + +sleep 5 + +terrad tx wasm instantiate 1 {} --label test --no-admin --from test0 --keyring-backend test --home mytestnet -y + +sleep 5 + +terrad tx wasm instantiate 1 {} --label test --no-admin --from test0 --keyring-backend test --home mytestnet -y + +sleep 5 + +contract_address0=$(terrad q wasm list-contract-by-code 1 --output json | jq -r '.contracts[0]') +contract_address1=$(terrad q wasm list-contract-by-code 1 --output json | jq -r '.contracts[1]') + +echo "Contract_addr0:" $contract_address0 +echo "Contract_addr1:" $contract_address1 + +recipient=$(terrad keys show test1 --keyring-backend test --home mytestnet --output json | jq -r '.address') + +echo "Recipient:" $recipient + +sleep 5 + +terrad tx wasm execute $contract_address0 '{"forward_to_contract":{"contract":"'$contract_address1'","recipient":"'$recipient'","amount":"10000"}}' --from test0 --keyring-backend test --home mytestnet --amount 10000uluna --gas 500000 + +# terra14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9ssrc8au \ No newline at end of file diff --git a/draft_metadata.json b/draft_metadata.json new file mode 100644 index 000000000..616d00a39 --- /dev/null +++ b/draft_metadata.json @@ -0,0 +1,8 @@ +{ + "title": "title", + "authors": "genuine", + "summary": "summary", + "details": "details", + "proposal_forum_url": "idkhttps://github.com/cosmos/chain-registry/blob/master/terra/chain.json", + "vote_option_context": "asd" +} \ No newline at end of file diff --git a/draft_proposal.json b/draft_proposal.json new file mode 100644 index 000000000..583ef80e3 --- /dev/null +++ b/draft_proposal.json @@ -0,0 +1,17 @@ +{ + "messages": [ + { + "@type": "/cosmos.upgrade.v1beta1.MsgSoftwareUpgrade", + "authority": "terra10d07y265gmmuvt4z0w9aw880jnsr700juxf95n", + "plan": { + "name": "", + "time": "0001-01-01T00:00:00Z", + "height": "0", + "info": "", + "upgraded_client_state": null + } + } + ], + "metadata": "ipfs://CID", + "deposit": "100uluna" +} \ No newline at end of file diff --git a/forwarder.wasm b/forwarder.wasm new file mode 100644 index 000000000..a2e7a4794 Binary files /dev/null and b/forwarder.wasm differ diff --git a/forwarder2.wasm b/forwarder2.wasm new file mode 100644 index 000000000..cbc7cbd37 Binary files /dev/null and b/forwarder2.wasm differ diff --git a/forwarder3.wasm b/forwarder3.wasm new file mode 100644 index 000000000..d04428c3e Binary files /dev/null and b/forwarder3.wasm differ diff --git a/forwarder4.wasm b/forwarder4.wasm new file mode 100644 index 000000000..31f7babf0 Binary files /dev/null and b/forwarder4.wasm differ diff --git a/lmao.json b/lmao.json new file mode 100644 index 000000000..32aa05be8 --- /dev/null +++ b/lmao.json @@ -0,0 +1,24 @@ +{ + "messages": [ + { + "@type": "/cosmos.gov.v1.MsgExecLegacyContent", + "authority": "terra10d07y265gmmuvt4z0w9aw880jnsr700juxf95n", + "content": { + "@type": "/cosmos.params.v1beta1.ParameterChangeProposal", + "title": "Increase Validator Active Set to 130", + "changes": [ + { + "key": "MaxValidators", + "value": "130", + "subspace": "staking" + } + ], + "description": "This proposal raises the validator limit for Luna Classic from 100 to 130, welcoming back validators from Luna v2 after the TFL and SEC settlement. Expanding the validator set strengthens our network's decentralization and benefits the LUNC community." + } + } + ], + "metadata": "Payment for genuine labs. More detailed info here : https://hackmd.io/@O2c-4nD0Qz6e_DUjqIEGrw/rymdK8L9p", + "deposit": "100000000000uluna", + "title": "Genuine Labs's Community Spend Proposal", + "summary": "Genuine Labs's Community Spend Proposal" +} \ No newline at end of file diff --git a/lmao2.json b/lmao2.json new file mode 100644 index 000000000..7e15a1a7e --- /dev/null +++ b/lmao2.json @@ -0,0 +1,20 @@ +{ + "messages": [ + { + "@type": "/cosmos.staking.v1beta1.MsgUpdateParams", + "authority": "terra10d07y265gmmuvt4z0w9aw880jnsr700juxf95n", + "params": { + "unbonding_time": "1814400s", + "max_validators": "130", + "max_entries": 7, + "historical_entries": 10000, + "bond_denom": "uluna", + "min_commission_rate": "0.000000000000000000" + } + } + ], + "metadata": "AQ==", + "deposit": "100000000000uluna", + "title": "Change max vals prop", + "summary": "Change max vals prop" +} diff --git a/prop.json b/prop.json new file mode 100644 index 000000000..c3dc91685 --- /dev/null +++ b/prop.json @@ -0,0 +1,17 @@ +{ + "title": "Proposal to decrease MaxBlockSize", + "description": "Proposal to decrease MaxBlockSize from 5mb to 2mb to avoid peer-to-peer spams", + + "changes": [ + { + "subspace": "baseapp", + "key": "BlockParams", + "value": { + "max_bytes": "2000000", + "max_gas": "100000000" + } + } + ], + "metadata": "AQ==", + "deposit": "1000000000000uluna" +} diff --git a/proto/terra/tax2gas/v1beta1/genesis.proto b/proto/terra/tax2gas/v1beta1/genesis.proto index 096f0640f..d2949d4b3 100644 --- a/proto/terra/tax2gas/v1beta1/genesis.proto +++ b/proto/terra/tax2gas/v1beta1/genesis.proto @@ -2,10 +2,26 @@ syntax = "proto3"; package terra.tax2gas.v1beta1; import "gogoproto/gogo.proto"; +import "cosmos/base/v1beta1/coin.proto"; -option go_package = "github.com/classic-terra/core/v3/x/tax2gas/types"; -message Params {} +message Params { + option (gogoproto.equal) = true; + option (gogoproto.goproto_stringer) = true; + + string burn_rate = 1 [ + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", + (gogoproto.nullable) = false + ]; + + repeated cosmos.base.v1beta1.DecCoin gas_prices = 2 [ + (gogoproto.moretags) = "yaml:\"gas_prices\"", + (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.DecCoins", + (gogoproto.nullable) = false + ]; +} + +option go_package = "github.com/classic-terra/core/v3/x/tax2gas/types"; // GenesisState defines the tax2gas module's genesis state. message GenesisState { diff --git a/proto/terra/tax2gas/v1beta1/query.proto b/proto/terra/tax2gas/v1beta1/query.proto index 85a50c94d..78bab4adb 100644 --- a/proto/terra/tax2gas/v1beta1/query.proto +++ b/proto/terra/tax2gas/v1beta1/query.proto @@ -8,13 +8,13 @@ import "terra/tax2gas/v1beta1/genesis.proto"; option go_package = "github.com/classic-terra/core/v3/x/tax2gas/types"; service Query { - rpc Params(ParamsRequest) returns (ParamsResponse) { + rpc Params(QueryParamsRequest) returns (QueryParamsResponse) { option (google.api.http).get = "/terra/tax2gas/Params"; } } //=============================== Params -message ParamsRequest {} -message ParamsResponse { +message QueryParamsRequest {} +message QueryParamsResponse { Params params = 1 [(gogoproto.nullable) = false]; } \ No newline at end of file diff --git a/x/tax2gas/ante/fee.go b/x/tax2gas/ante/fee.go index 5408cd38e..d8c99cdbb 100644 --- a/x/tax2gas/ante/fee.go +++ b/x/tax2gas/ante/fee.go @@ -10,6 +10,7 @@ import ( "github.com/cosmos/cosmos-sdk/x/auth/ante" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + tax2gasKeeper "github.com/classic-terra/core/v3/x/tax2gas/keeper" "github.com/classic-terra/core/v3/x/tax2gas/types" ) @@ -22,14 +23,16 @@ type FeeDecorator struct { bankKeeper types.BankKeeper feegrantKeeper ante.FeegrantKeeper treasuryKeeper types.TreasuryKeeper + tax2gasKeeper tax2gasKeeper.Keeper } -func NewFeeDecorator(ak ante.AccountKeeper, bk types.BankKeeper, fk ante.FeegrantKeeper, tk types.TreasuryKeeper) FeeDecorator { +func NewFeeDecorator(ak ante.AccountKeeper, bk types.BankKeeper, fk ante.FeegrantKeeper, tk types.TreasuryKeeper, taxKeeper tax2gasKeeper.Keeper) FeeDecorator { return FeeDecorator{ accountKeeper: ak, bankKeeper: bk, feegrantKeeper: fk, treasuryKeeper: tk, + tax2gasKeeper: taxKeeper, } } @@ -49,8 +52,25 @@ func (fd FeeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, nex ) msgs := feeTx.GetMsgs() - // Compute taxes - taxes := FilterMsgAndComputeTax(ctx, fd.treasuryKeeper, msgs...) + + // Compute taxes based on consumed gas + gasConsumed := ctx.GasMeter().GasConsumed() + taxRequired, err := fd.tax2gasKeeper.ComputeTaxOnGasConsumed(ctx, tx, fd.treasuryKeeper, gasConsumed) + if err != nil { + return ctx, err + } + + // Compute taxes based on sent amount + taxes := tax2gasKeeper.FilterMsgAndComputeTax(ctx, fd.treasuryKeeper, msgs...) + // Convert taxes to gas + taxGas, err := fd.tax2gasKeeper.ComputeGas(ctx, tx, taxes) + if err != nil { + return ctx, err + } + + if feeTx.GetGas() < taxGas { + return ctx, errorsmod.Wrap(sdkerrors.ErrInvalidGasLimit, "must provide enough gas to cover taxes") + } if !simulate { priority, err = fd.checkTxFee(ctx, tx, taxes) @@ -59,34 +79,54 @@ func (fd FeeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, nex } } - if err := fd.checkDeductFee(ctx, feeTx, taxes, simulate); err != nil { + // Try to deduct the required tax from the consumed gas + feeDenom, err := fd.checkDeductFee(ctx, feeTx, taxRequired, simulate) + if err != nil { return ctx, err } - newCtx := ctx.WithPriority(priority) - + newCtx := ctx.WithPriority(priority).WithValue(types.ConsumedGasFee, taxRequired).WithValue(types.TaxGas, taxGas) + if feeDenom != "" { + newCtx = newCtx.WithValue(types.FeeDenom, feeDenom) + } return next(newCtx, tx, simulate) } -func (fd FeeDecorator) checkDeductFee(ctx sdk.Context, feeTx sdk.FeeTx, taxes sdk.Coins, simulate bool) error { +func (fd FeeDecorator) checkDeductFee(ctx sdk.Context, feeTx sdk.FeeTx, taxes sdk.Coins, simulate bool) (string, error) { if addr := fd.accountKeeper.GetModuleAddress(authtypes.FeeCollectorName); addr == nil { - return fmt.Errorf("fee collector module account (%s) has not been set", authtypes.FeeCollectorName) + return "", fmt.Errorf("fee collector module account (%s) has not been set", authtypes.FeeCollectorName) } - fee := feeTx.GetFee() + feeCoins := feeTx.GetFee() feePayer := feeTx.FeePayer() feeGranter := feeTx.FeeGranter() deductFeesFrom := feePayer + var foundCoins sdk.Coins + + if !taxes.IsZero() { + for _, coin := range feeCoins { + found, requiredFee := taxes.Find(coin.Denom) + if !found { + continue + } + if coin.Amount.GT(requiredFee.Amount) { + foundCoins = sdk.NewCoins(requiredFee) + } + } + } else { + return "", nil + } + // if feegranter set deduct fee from feegranter account. // this works with only when feegrant enabled. if feeGranter != nil { if fd.feegrantKeeper == nil { - return sdkerrors.ErrInvalidRequest.Wrap("fee grants are not enabled") + return "", sdkerrors.ErrInvalidRequest.Wrap("fee grants are not enabled") } else if !feeGranter.Equals(feePayer) { - err := fd.feegrantKeeper.UseGrantedFees(ctx, feeGranter, feePayer, fee, feeTx.GetMsgs()) + err := fd.feegrantKeeper.UseGrantedFees(ctx, feeGranter, feePayer, foundCoins, feeTx.GetMsgs()) if err != nil { - return errorsmod.Wrapf(err, "%s does not not allow to pay fees for %s", feeGranter, feePayer) + return "", errorsmod.Wrapf(err, "%s does not not allow to pay fees for %s", feeGranter, feePayer) } } @@ -95,37 +135,39 @@ func (fd FeeDecorator) checkDeductFee(ctx sdk.Context, feeTx sdk.FeeTx, taxes sd deductFeesFromAcc := fd.accountKeeper.GetAccount(ctx, deductFeesFrom) if deductFeesFromAcc == nil { - return sdkerrors.ErrUnknownAddress.Wrapf("fee payer address: %s does not exist", deductFeesFrom) + return "", sdkerrors.ErrUnknownAddress.Wrapf("fee payer address: %s does not exist", deductFeesFrom) } // deduct the fees - if !fee.IsZero() { - err := DeductFees(fd.bankKeeper, ctx, deductFeesFromAcc, fee) + if !foundCoins.IsZero() { + err := DeductFees(fd.bankKeeper, ctx, deductFeesFromAcc, foundCoins) if err != nil { - return err + return "", err } - - if !taxes.IsZero() && !simulate { - err := fd.BurnTaxSplit(ctx, taxes) + if !foundCoins.IsZero() && !simulate { + err := fd.BurnTaxSplit(ctx, foundCoins) if err != nil { - return err + return "", err } // Record tax proceeds - fd.treasuryKeeper.RecordEpochTaxProceeds(ctx, taxes) + fd.treasuryKeeper.RecordEpochTaxProceeds(ctx, foundCoins) } - } - events := sdk.Events{ - sdk.NewEvent( - sdk.EventTypeTx, - sdk.NewAttribute(sdk.AttributeKeyFee, fee.String()), - sdk.NewAttribute(sdk.AttributeKeyFeePayer, deductFeesFrom.String()), - ), - } - ctx.EventManager().EmitEvents(events) + events := sdk.Events{ + sdk.NewEvent( + sdk.EventTypeTx, + sdk.NewAttribute(sdk.AttributeKeyFee, foundCoins.String()), + sdk.NewAttribute(sdk.AttributeKeyFeePayer, deductFeesFrom.String()), + ), + } + ctx.EventManager().EmitEvents(events) - return nil + // As there is only 1 element + return foundCoins.Denoms()[0], nil + } else { + return "", fmt.Errorf("can't find coin that matches. Expected %s, wanted %s", feeCoins, taxes) + } } // DeductFees deducts fees from the given account. @@ -156,23 +198,17 @@ func (fd FeeDecorator) checkTxFee(ctx sdk.Context, tx sdk.Tx, taxes sdk.Coins) ( gas := feeTx.GetGas() msgs := feeTx.GetMsgs() isOracleTx := isOracleTx(msgs) + gasPrices := fd.tax2gasKeeper.GetGasPrices(ctx) // Ensure that the provided fees meet a minimum threshold for the validator, // if this is a CheckTx. This is only for local mempool purposes, and thus // is only ran on check tx. + requiredGasFees := make(sdk.Coins, len(gasPrices)) if ctx.IsCheckTx() && !isOracleTx { - requiredGasFees := sdk.Coins{} - minGasPrices := ctx.MinGasPrices() - if !minGasPrices.IsZero() { - requiredGasFees = make(sdk.Coins, len(minGasPrices)) - - // Determine the required fees by multiplying each required minimum gas - // price by the gas limit, where fee = ceil(minGasPrice * gasLimit). - glDec := sdk.NewDec(int64(gas)) - for i, gp := range minGasPrices { - fee := gp.Amount.Mul(glDec) - requiredGasFees[i] = sdk.NewCoin(gp.Denom, fee.Ceil().RoundInt()) - } + glDec := sdk.NewDec(int64(gas)) + for i, gp := range gasPrices { + fee := gp.Amount.Mul(glDec) + requiredGasFees[i] = sdk.NewCoin(gp.Denom, fee.Ceil().RoundInt()) } requiredFees := requiredGasFees.Add(taxes...) diff --git a/x/tax2gas/client/cli/query.go b/x/tax2gas/client/cli/query.go index ffd212794..fffdca4c1 100644 --- a/x/tax2gas/client/cli/query.go +++ b/x/tax2gas/client/cli/query.go @@ -42,7 +42,7 @@ func GetCmdQueryParams() *cobra.Command { } queryClient := types.NewQueryClient(clientCtx) - params := &types.ParamsRequest{} + params := &types.QueryParamsRequest{} res, err := queryClient.Params(context.Background(), params) if err != nil { diff --git a/x/tax2gas/genesis.go b/x/tax2gas/genesis.go new file mode 100644 index 000000000..0ef46e9f7 --- /dev/null +++ b/x/tax2gas/genesis.go @@ -0,0 +1,14 @@ +package module + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/classic-terra/core/v3/x/tax2gas/keeper" + "github.com/classic-terra/core/v3/x/tax2gas/types" +) + +// InitGenesis initializes default parameters +// and the keeper's address to pubkey map +func InitGenesis(ctx sdk.Context, keeper keeper.Keeper, data *types.GenesisState) { + keeper.SetParams(ctx, data.Params) +} diff --git a/x/tax2gas/keeper/expected_keeper.go b/x/tax2gas/keeper/expected_keeper.go new file mode 100644 index 000000000..58af418ae --- /dev/null +++ b/x/tax2gas/keeper/expected_keeper.go @@ -0,0 +1,41 @@ +package keeper + +import ( + "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" + distributiontypes "github.com/cosmos/cosmos-sdk/x/distribution/types" + govv1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1" +) + +// TreasuryKeeper for tax charging & recording +type TreasuryKeeper interface { + RecordEpochTaxProceeds(ctx sdk.Context, delta sdk.Coins) + GetTaxRate(ctx sdk.Context) (taxRate sdk.Dec) + GetTaxCap(ctx sdk.Context, denom string) (taxCap math.Int) + GetBurnSplitRate(ctx sdk.Context) sdk.Dec + HasBurnTaxExemptionAddress(ctx sdk.Context, addresses ...string) bool + HasBurnTaxExemptionContract(ctx sdk.Context, address string) bool + GetMinInitialDepositRatio(ctx sdk.Context) sdk.Dec +} + +// OracleKeeper for feeder validation +type OracleKeeper interface { + ValidateFeeder(ctx sdk.Context, feederAddr sdk.AccAddress, validatorAddr sdk.ValAddress) error +} + +// BankKeeper defines the contract needed for supply related APIs (noalias) +type BankKeeper interface { + IsSendEnabledCoins(ctx sdk.Context, coins ...sdk.Coin) error + SendCoins(ctx sdk.Context, from, to sdk.AccAddress, amt sdk.Coins) error + SendCoinsFromAccountToModule(ctx sdk.Context, senderAddr sdk.AccAddress, recipientModule string, amt sdk.Coins) error + SendCoinsFromModuleToModule(ctx sdk.Context, senderModule string, recipientModule string, amt sdk.Coins) error +} + +type DistrKeeper interface { + FundCommunityPool(ctx sdk.Context, amount sdk.Coins, sender sdk.AccAddress) error + GetFeePool(ctx sdk.Context) distributiontypes.FeePool +} + +type GovKeeper interface { + GetDepositParams(ctx sdk.Context) govv1.DepositParams +} diff --git a/x/tax2gas/keeper/keeper.go b/x/tax2gas/keeper/keeper.go index 126fc876d..b64f13f0c 100644 --- a/x/tax2gas/keeper/keeper.go +++ b/x/tax2gas/keeper/keeper.go @@ -1,6 +1,11 @@ package keeper import ( + "fmt" + + "github.com/cometbft/cometbft/libs/log" + + "github.com/cosmos/cosmos-sdk/codec" storetypes "github.com/cosmos/cosmos-sdk/store/types" sdk "github.com/cosmos/cosmos-sdk/types" paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" @@ -10,31 +15,21 @@ import ( type Keeper struct { storeKey storetypes.StoreKey + cdc codec.BinaryCodec paramSpace paramtypes.Subspace } -func NewKeeper(storeKey storetypes.StoreKey, paramSpace paramtypes.Subspace) *Keeper { +func NewKeeper(cdc codec.BinaryCodec, storeKey storetypes.StoreKey, paramSpace paramtypes.Subspace) Keeper { // set KeyTable if it has not already been set if !paramSpace.HasKeyTable() { paramSpace = paramSpace.WithKeyTable(types.ParamKeyTable()) } - return &Keeper{storeKey: storeKey, paramSpace: paramSpace} -} - -// GetParams returns the total set of testmodule parameters. -func (k Keeper) GetParams(ctx sdk.Context) (params types.Params) { - k.paramSpace.GetParamSet(ctx, ¶ms) - return params -} - -// SetParams sets the total set of testmodule parameters. -func (k Keeper) SetParams(ctx sdk.Context, params types.Params) { - k.paramSpace.SetParamSet(ctx, ¶ms) + return Keeper{cdc: cdc, storeKey: storeKey, paramSpace: paramSpace} } -// InitGenesis initializes the testmodule module's state from a provided genesis +// InitGenesis initializes the tax2gas module's state from a provided genesis // state. func (k Keeper) InitGenesis(ctx sdk.Context, genState *types.GenesisState) { if err := genState.Validate(); err != nil { @@ -44,9 +39,22 @@ func (k Keeper) InitGenesis(ctx sdk.Context, genState *types.GenesisState) { k.SetParams(ctx, genState.Params) } -// ExportGenesis returns the testmodule module's exported genesis. +// ExportGenesis returns the tax2gas module's exported genesis. func (k Keeper) ExportGenesis(ctx sdk.Context) *types.GenesisState { return &types.GenesisState{ Params: k.GetParams(ctx), } } + +func (k Keeper) GetBurnRate(ctx sdk.Context) sdk.Dec { + return k.GetParams(ctx).BurnRate +} + +func (k Keeper) GetGasPrices(ctx sdk.Context) sdk.DecCoins { + return k.GetParams(ctx).GasPrices +} + +// Logger returns a module-specific logger. +func (k Keeper) Logger(ctx sdk.Context) log.Logger { + return ctx.Logger().With("module", fmt.Sprintf("x/%s", types.ModuleName)) +} diff --git a/x/tax2gas/keeper/params.go b/x/tax2gas/keeper/params.go new file mode 100644 index 000000000..ac87194f1 --- /dev/null +++ b/x/tax2gas/keeper/params.go @@ -0,0 +1,31 @@ +package keeper + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/classic-terra/core/v3/x/tax2gas/types" +) + +// SetParams sets the gov module's parameters. +func (k Keeper) SetParams(ctx sdk.Context, params types.Params) error { + store := ctx.KVStore(k.storeKey) + bz, err := k.cdc.Marshal(¶ms) + if err != nil { + return err + } + store.Set(types.ParamsKey, bz) + + return nil +} + +// GetParams gets the gov module's parameters. +func (k Keeper) GetParams(clientCtx sdk.Context) (params types.Params) { + store := clientCtx.KVStore(k.storeKey) + bz := store.Get(types.ParamsKey) + if bz == nil { + return params + } + + k.cdc.MustUnmarshal(bz, ¶ms) + return params +} diff --git a/x/tax2gas/keeper/querier.go b/x/tax2gas/keeper/querier.go new file mode 100644 index 000000000..9f715830f --- /dev/null +++ b/x/tax2gas/keeper/querier.go @@ -0,0 +1,28 @@ +package keeper + +import ( + "context" + + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/classic-terra/core/v3/x/tax2gas/types" +) + +// querier is used as Keeper will have duplicate methods if used directly, and gRPC names take precedence over q +type querier struct { + Keeper +} + +// NewQuerier returns an implementation of the market QueryServer interface +// for the provided Keeper. +func NewQuerier(keeper Keeper) types.QueryServer { + return &querier{Keeper: keeper} +} + +var _ types.QueryServer = querier{} + +// Params queries params of dyncomm module +func (q querier) Params(c context.Context, _ *types.QueryParamsRequest) (*types.QueryParamsResponse, error) { + ctx := sdk.UnwrapSDKContext(c) + return &types.QueryParamsResponse{Params: q.GetParams(ctx)}, nil +} diff --git a/x/tax2gas/keeper/tax.go b/x/tax2gas/keeper/tax.go new file mode 100644 index 000000000..80a28d696 --- /dev/null +++ b/x/tax2gas/keeper/tax.go @@ -0,0 +1,190 @@ +package keeper + +import ( + "regexp" + "strings" + + errorsmod "cosmossdk.io/errors" + "cosmossdk.io/math" + wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + authz "github.com/cosmos/cosmos-sdk/x/authz" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + + marketexported "github.com/classic-terra/core/v3/x/market/exported" + oracleexported "github.com/classic-terra/core/v3/x/oracle/exported" +) + +var IBCRegexp = regexp.MustCompile("^ibc/[a-fA-F0-9]{64}$") + +func isIBCDenom(denom string) bool { + return IBCRegexp.MatchString(strings.ToLower(denom)) +} + +// FilterMsgAndComputeTax computes the stability tax on messages. +func FilterMsgAndComputeTax(ctx sdk.Context, tk TreasuryKeeper, msgs ...sdk.Msg) sdk.Coins { + taxes := sdk.Coins{} + + for _, msg := range msgs { + switch msg := msg.(type) { + case *banktypes.MsgSend: + if !tk.HasBurnTaxExemptionAddress(ctx, msg.FromAddress, msg.ToAddress) { + taxes = taxes.Add(computeTax(ctx, tk, msg.Amount)...) + } + + case *banktypes.MsgMultiSend: + tainted := 0 + + for _, input := range msg.Inputs { + if tk.HasBurnTaxExemptionAddress(ctx, input.Address) { + tainted++ + } + } + + for _, output := range msg.Outputs { + if tk.HasBurnTaxExemptionAddress(ctx, output.Address) { + tainted++ + } + } + + if tainted != len(msg.Inputs)+len(msg.Outputs) { + for _, input := range msg.Inputs { + taxes = taxes.Add(computeTax(ctx, tk, input.Coins)...) + } + } + + case *marketexported.MsgSwapSend: + taxes = taxes.Add(computeTax(ctx, tk, sdk.NewCoins(msg.OfferCoin))...) + + case *wasmtypes.MsgInstantiateContract: + taxes = taxes.Add(computeTax(ctx, tk, msg.Funds)...) + + case *wasmtypes.MsgInstantiateContract2: + taxes = taxes.Add(computeTax(ctx, tk, msg.Funds)...) + + case *wasmtypes.MsgExecuteContract: + if !tk.HasBurnTaxExemptionContract(ctx, msg.Contract) { + taxes = taxes.Add(computeTax(ctx, tk, msg.Funds)...) + } + + case *authz.MsgExec: + messages, err := msg.GetMessages() + if err == nil { + taxes = taxes.Add(FilterMsgAndComputeTax(ctx, tk, messages...)...) + } + } + } + + return taxes +} + +// computes the stability tax according to tax-rate and tax-cap +func computeTax(ctx sdk.Context, tk TreasuryKeeper, principal sdk.Coins) sdk.Coins { + taxRate := tk.GetTaxRate(ctx) + if taxRate.Equal(sdk.ZeroDec()) { + return sdk.Coins{} + } + + taxes := sdk.Coins{} + + for _, coin := range principal { + if coin.Denom == sdk.DefaultBondDenom { + continue + } + + if isIBCDenom(coin.Denom) { + continue + } + + taxDue := sdk.NewDecFromInt(coin.Amount).Mul(taxRate).TruncateInt() + + // If tax due is greater than the tax cap, cap! + taxCap := tk.GetTaxCap(ctx, coin.Denom) + if taxDue.GT(taxCap) { + taxDue = taxCap + } + + if taxDue.Equal(sdk.ZeroInt()) { + continue + } + + taxes = taxes.Add(sdk.NewCoin(coin.Denom, taxDue)) + } + + return taxes +} + +func (k Keeper) ComputeTaxOnGasConsumed(ctx sdk.Context, tx sdk.Tx, tk TreasuryKeeper, gas uint64) (sdk.Coins, error) { + feeTx, ok := tx.(sdk.FeeTx) + if !ok { + return nil, errorsmod.Wrap(sdkerrors.ErrTxDecode, "Tx must be a FeeTx") + } + + feeCoins := feeTx.GetFee() + isOracleTx := isOracleTx(feeTx.GetMsgs()) + gasPrices := k.GetGasPrices(ctx) + + gasFees := make(sdk.Coins, len(gasPrices)) + if !isOracleTx && len(gasPrices) != 0 { + // Determine the required fees by multiplying each required minimum gas + // price by the gas limit, where fee = ceil(minGasPrice * gasLimit). + glDec := sdk.NewDec(int64(gas)) + for i, gp := range gasPrices { + fee := gp.Amount.Mul(glDec) + gasFees[i] = sdk.NewCoin(gp.Denom, fee.Ceil().RoundInt()) + } + + // Check required fees + if !feeCoins.IsAnyGTE(gasFees) { + return nil, errorsmod.Wrapf(sdkerrors.ErrInsufficientFee, "insufficient gas fees; got: %q, required: %q ", feeCoins, gasFees) + } + } + + return gasFees, nil +} + +func (k Keeper) ComputeGas(ctx sdk.Context, tx sdk.Tx, taxes sdk.Coins) (uint64, error) { + feeTx, ok := tx.(sdk.FeeTx) + if !ok { + return 0, errorsmod.Wrap(sdkerrors.ErrTxDecode, "Tx must be a FeeTx") + } + + isOracleTx := isOracleTx(feeTx.GetMsgs()) + gasPrices := k.GetGasPrices(ctx).Sort() + taxes = taxes.Sort() + + var tax2gas math.Int = math.ZeroInt() + if ctx.IsCheckTx() && !isOracleTx { + // Convert to gas + var i, j int = 0, 0 + for i < len(gasPrices) && j < len(taxes) { + if gasPrices[i].Denom == taxes[j].Denom { + tax2gas = tax2gas.Add(math.Int(sdk.NewDec(taxes[j].Amount.Int64()).Quo((gasPrices[i].Amount)).Ceil().RoundInt())) + i++ + j++ + } else if gasPrices[i].Denom < taxes[j].Denom { + i++ + } else { + j++ + } + } + } + + return tax2gas.Uint64(), nil +} + +func isOracleTx(msgs []sdk.Msg) bool { + for _, msg := range msgs { + switch msg.(type) { + case *oracleexported.MsgAggregateExchangeRatePrevote: + continue + case *oracleexported.MsgAggregateExchangeRateVote: + continue + default: + return false + } + } + + return true +} diff --git a/x/tax2gas/module.go b/x/tax2gas/module.go index 213548bf3..b7dbd635f 100644 --- a/x/tax2gas/module.go +++ b/x/tax2gas/module.go @@ -24,7 +24,9 @@ var ( _ module.AppModuleBasic = AppModuleBasic{} ) -type AppModuleBasic struct{} +type AppModuleBasic struct { + cdc codec.Codec +} func (AppModuleBasic) Name() string { return types.ModuleName } @@ -36,7 +38,7 @@ func (AppModuleBasic) DefaultGenesis(cdc codec.JSONCodec) json.RawMessage { return cdc.MustMarshalJSON(types.DefaultGenesis()) } -// ValidateGenesis performs genesis state validation for the testmodule module. +// ValidateGenesis performs genesis state validation for the tax2gas module. func (AppModuleBasic) ValidateGenesis(cdc codec.JSONCodec, config client.TxEncodingConfig, bz json.RawMessage) error { var genState types.GenesisState if err := cdc.UnmarshalJSON(bz, &genState); err != nil { @@ -61,7 +63,7 @@ func (b AppModuleBasic) GetQueryCmd() *cobra.Command { return cli.GetQueryCmd() } -// RegisterInterfaces registers interfaces and implementations of the testmodule module. +// RegisterInterfaces registers interfaces and implementations of the tax2gas module. func (AppModuleBasic) RegisterInterfaces(registry codectypes.InterfaceRegistry) { types.RegisterInterfaces(registry) } @@ -73,35 +75,36 @@ type AppModule struct { } func (am AppModule) RegisterServices(cfg module.Configurator) { - // types.RegisterMsgServer(cfg.MsgServer(), testmodule.NewMsgServerImpl(&am.k)) + // types.RegisterMsgServer(cfg.MsgServer(), tax2gas.NewMsgServerImpl(&am.k)) // queryproto.RegisterQueryServer(cfg.QueryServer(), grpc.Querier{Q: module.NewQuerier(am.k)}) + querier := keeper.NewQuerier(am.k) + types.RegisterQueryServer(cfg.QueryServer(), querier) } -func NewAppModule(testmoduleKeeper keeper.Keeper) AppModule { +func NewAppModule(cdc codec.Codec, tax2gasKeeper keeper.Keeper) AppModule { return AppModule{ - AppModuleBasic: AppModuleBasic{}, - k: testmoduleKeeper, + AppModuleBasic: AppModuleBasic{cdc}, + k: tax2gasKeeper, } } func (am AppModule) RegisterInvariants(ir sdk.InvariantRegistry) { } -// QuerierRoute returns the testmodule module's querier route name. +// QuerierRoute returns the tax2gas module's querier route name. func (AppModule) QuerierRoute() string { return types.RouterKey } -// InitGenesis performs genesis initialization for the testmodule module. +// InitGenesis performs genesis initialization for the tax2gas module. // no validator updates. func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, gs json.RawMessage) []abci.ValidatorUpdate { var genesisState types.GenesisState cdc.MustUnmarshalJSON(gs, &genesisState) - - am.k.InitGenesis(ctx, &genesisState) + InitGenesis(ctx, am.k, &genesisState) return []abci.ValidatorUpdate{} } -// ExportGenesis returns the exported genesis state as raw bytes for the testmodule. +// ExportGenesis returns the exported genesis state as raw bytes for the tax2gas. // module. func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) json.RawMessage { genState := am.k.ExportGenesis(ctx) diff --git a/x/tax2gas/post/post.go b/x/tax2gas/post/post.go new file mode 100644 index 000000000..430c75293 --- /dev/null +++ b/x/tax2gas/post/post.go @@ -0,0 +1,98 @@ +package post + +import ( + errorsmod "cosmossdk.io/errors" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/cosmos/cosmos-sdk/x/auth/ante" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + + tax2gasKeeper "github.com/classic-terra/core/v3/x/tax2gas/keeper" + "github.com/classic-terra/core/v3/x/tax2gas/types" +) + +type Tax2gasPostDecorator struct { + accountKeeper ante.AccountKeeper + bankKeeper types.BankKeeper + treasuryKeeper types.TreasuryKeeper + tax2gasKeeper tax2gasKeeper.Keeper +} + +func NewTax2GasPostDecorator(accountKeeper ante.AccountKeeper, bankKeeper types.BankKeeper, treasuryKeeper types.TreasuryKeeper, tax2gasKeeper tax2gasKeeper.Keeper) Tax2gasPostDecorator { + return Tax2gasPostDecorator{ + accountKeeper: accountKeeper, + bankKeeper: bankKeeper, + treasuryKeeper: treasuryKeeper, + tax2gasKeeper: tax2gasKeeper, + } +} + +func (dd Tax2gasPostDecorator) PostHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, success bool, next sdk.PostHandler) (sdk.Context, error) { + feeTx, ok := tx.(sdk.FeeTx) + if !ok { + return ctx, errorsmod.Wrap(sdkerrors.ErrTxDecode, "Tx must be a FeeTx") + } + + if !simulate && ctx.BlockHeight() > 0 && feeTx.GetGas() == 0 { + return ctx, errorsmod.Wrap(sdkerrors.ErrInvalidGasLimit, "must provide positive gas") + } + + feeCoins := feeTx.GetFee() + paidFees := ctx.Value(types.ConsumedGasFee) + paidFeeCoins, ok := paidFees.(sdk.Coins) + if !ok { + return ctx, errorsmod.Wrap(types.ErrParsing, "Error parsing coins") + } + + taxGas, ok := ctx.Value(types.TaxGas).(uint64) + if !ok { + // TODO + return ctx, errorsmod.Wrap(types.ErrParsing, "Error parsing tax gas") + } + // we consume the gas here as we need to calculate the tax for consumed gas + ctx.GasMeter().ConsumeGas(taxGas, "tax gas") + + gasConsumed := ctx.GasMeter().GasConsumed() + taxRequired, err := dd.tax2gasKeeper.ComputeTaxOnGasConsumed(ctx, tx, dd.treasuryKeeper, gasConsumed) + if err != nil { + return ctx, err + } + + if simulate { + return next(ctx, tx, simulate, success) + } + + var requiredFees sdk.Coins + if taxRequired != nil && feeCoins != nil { + requiredFees = taxRequired.Sub(paidFeeCoins...) + + // Check if fee coins contains at least one coin that can cover required fees + if !feeCoins.IsAnyGTE(requiredFees) { + return ctx, errorsmod.Wrapf(sdkerrors.ErrInsufficientFee, "insufficient fees; got: %q, required: %q", feeCoins, requiredFees) + } + + feeDenom, ok := ctx.Value(types.FeeDenom).(string) + if !ok { + return ctx, errorsmod.Wrap(types.ErrParsing, "Error parsing fee denom") + } + + found, requiredFee := requiredFees.Find(feeDenom) + if !found { + return ctx, errorsmod.Wrapf(types.ErrCoinNotFound, "can'f find %s in %s", feeDenom, requiredFees) + } + remainingCoins := feeCoins.Sub(requiredFee) + + if !remainingCoins.IsValid() { + return ctx, errorsmod.Wrapf(sdkerrors.ErrInvalidCoins, "invalid remaining coins amount: %s", remainingCoins) + } + + feePayer := dd.accountKeeper.GetAccount(ctx, feeTx.FeePayer()) + + err := dd.bankKeeper.SendCoinsFromAccountToModule(ctx, feePayer.GetAddress(), authtypes.FeeCollectorName, sdk.NewCoins(requiredFee)) + if err != nil { + return ctx, errorsmod.Wrapf(sdkerrors.ErrInsufficientFunds, err.Error()) + } + } + + return ctx, nil +} diff --git a/x/tax2gas/types/errors.go b/x/tax2gas/types/errors.go index ab1254f4c..04e40e3f4 100644 --- a/x/tax2gas/types/errors.go +++ b/x/tax2gas/types/errors.go @@ -1 +1,11 @@ package types + +import ( + errorsmod "cosmossdk.io/errors" +) + +// Market errors +var ( + ErrParsing = errorsmod.Register(ModuleName, 1, "Parsing errors") + ErrCoinNotFound = errorsmod.Register(ModuleName, 2, "Coin not found") +) diff --git a/x/tax2gas/types/expected_keeper.go b/x/tax2gas/types/expected_keeper.go index 945b25a72..8fbab7047 100644 --- a/x/tax2gas/types/expected_keeper.go +++ b/x/tax2gas/types/expected_keeper.go @@ -22,4 +22,5 @@ type BankKeeper interface { SendCoins(ctx sdk.Context, from, to sdk.AccAddress, amt sdk.Coins) error SendCoinsFromAccountToModule(ctx sdk.Context, senderAddr sdk.AccAddress, recipientModule string, amt sdk.Coins) error SendCoinsFromModuleToModule(ctx sdk.Context, senderModule string, recipientModule string, amt sdk.Coins) error + SendCoinsFromModuleToAccount(ctx sdk.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins) error } diff --git a/x/tax2gas/types/genesis.pb.go b/x/tax2gas/types/genesis.pb.go index fbadfca5d..b45e0f446 100644 --- a/x/tax2gas/types/genesis.pb.go +++ b/x/tax2gas/types/genesis.pb.go @@ -5,6 +5,8 @@ package types import ( fmt "fmt" + github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types" + types "github.com/cosmos/cosmos-sdk/types" _ "github.com/cosmos/gogoproto/gogoproto" proto "github.com/cosmos/gogoproto/proto" io "io" @@ -24,6 +26,8 @@ var _ = math.Inf const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package type Params struct { + BurnRate github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,1,opt,name=burn_rate,json=burnRate,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"burn_rate"` + GasPrices github_com_cosmos_cosmos_sdk_types.DecCoins `protobuf:"bytes,2,rep,name=gas_prices,json=gasPrices,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.DecCoins" json:"gas_prices" yaml:"gas_prices"` } func (m *Params) Reset() { *m = Params{} } @@ -59,6 +63,13 @@ func (m *Params) XXX_DiscardUnknown() { var xxx_messageInfo_Params proto.InternalMessageInfo +func (m *Params) GetGasPrices() github_com_cosmos_cosmos_sdk_types.DecCoins { + if m != nil { + return m.GasPrices + } + return nil +} + // GenesisState defines the tax2gas module's genesis state. type GenesisState struct { // params is the container of tax2gas parameters. @@ -115,23 +126,64 @@ func init() { } var fileDescriptor_589c4ef0e5113034 = []byte{ - // 209 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x52, 0x2e, 0x49, 0x2d, 0x2a, - 0x4a, 0xd4, 0x2f, 0x49, 0xac, 0x30, 0x4a, 0x4f, 0x2c, 0xd6, 0x2f, 0x33, 0x4c, 0x4a, 0x2d, 0x49, - 0x34, 0xd4, 0x4f, 0x4f, 0xcd, 0x4b, 0x2d, 0xce, 0x2c, 0xd6, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, - 0x12, 0x05, 0x2b, 0xd2, 0x83, 0x2a, 0xd2, 0x83, 0x2a, 0x92, 0x12, 0x49, 0xcf, 0x4f, 0xcf, 0x07, - 0xab, 0xd0, 0x07, 0xb1, 0x20, 0x8a, 0x95, 0x38, 0xb8, 0xd8, 0x02, 0x12, 0x8b, 0x12, 0x73, 0x8b, - 0x95, 0xbc, 0xb9, 0x78, 0xdc, 0x21, 0xe6, 0x04, 0x97, 0x24, 0x96, 0xa4, 0x0a, 0x59, 0x73, 0xb1, - 0x15, 0x80, 0x65, 0x24, 0x18, 0x15, 0x18, 0x35, 0xb8, 0x8d, 0x64, 0xf5, 0xb0, 0x9a, 0xab, 0x07, - 0xd1, 0xee, 0xc4, 0x72, 0xe2, 0x9e, 0x3c, 0x43, 0x10, 0x54, 0x8b, 0x93, 0xd7, 0x89, 0x47, 0x72, - 0x8c, 0x17, 0x1e, 0xc9, 0x31, 0x3e, 0x78, 0x24, 0xc7, 0x38, 0xe1, 0xb1, 0x1c, 0xc3, 0x85, 0xc7, - 0x72, 0x0c, 0x37, 0x1e, 0xcb, 0x31, 0x44, 0x19, 0xa4, 0x67, 0x96, 0x64, 0x94, 0x26, 0xe9, 0x25, - 0xe7, 0xe7, 0xea, 0x27, 0xe7, 0x24, 0x16, 0x17, 0x67, 0x26, 0xeb, 0x42, 0x7c, 0x95, 0x9c, 0x5f, - 0x94, 0xaa, 0x5f, 0x66, 0xac, 0x5f, 0x01, 0xf7, 0x5f, 0x49, 0x65, 0x41, 0x6a, 0x71, 0x12, 0x1b, - 0xd8, 0xa5, 0xc6, 0x80, 0x00, 0x00, 0x00, 0xff, 0xff, 0x8d, 0x3f, 0x48, 0x2e, 0xfd, 0x00, 0x00, - 0x00, + // 362 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x91, 0xb1, 0x4e, 0xeb, 0x30, + 0x18, 0x85, 0xe3, 0x7b, 0xaf, 0xaa, 0x36, 0xbd, 0xcb, 0xad, 0x2e, 0x52, 0x55, 0x41, 0x52, 0x05, + 0x09, 0x55, 0x42, 0xb5, 0x69, 0xbb, 0x95, 0x2d, 0x20, 0x81, 0xe8, 0x52, 0x85, 0x8d, 0xa5, 0x72, + 0x82, 0x15, 0x22, 0x9a, 0x38, 0xf2, 0xef, 0x56, 0xed, 0x03, 0xb0, 0x33, 0x32, 0x76, 0xe6, 0x49, + 0x3a, 0x76, 0x44, 0x0c, 0x05, 0xb5, 0x03, 0xcc, 0x3c, 0x01, 0x72, 0x1c, 0x0a, 0x03, 0x03, 0x93, + 0x2d, 0xf9, 0x9c, 0xe3, 0xef, 0xff, 0x8f, 0xb9, 0x2b, 0x99, 0x10, 0x94, 0x48, 0x3a, 0x69, 0x87, + 0x14, 0xc8, 0xb8, 0xe5, 0x33, 0x49, 0x5b, 0x24, 0x64, 0x09, 0x83, 0x08, 0x70, 0x2a, 0xb8, 0xe4, + 0x95, 0xad, 0x4c, 0x84, 0x73, 0x11, 0xce, 0x45, 0xb5, 0xff, 0x21, 0x0f, 0x79, 0xa6, 0x20, 0xea, + 0xa6, 0xc5, 0x35, 0x2b, 0xe0, 0x10, 0x73, 0x20, 0x3e, 0x05, 0xb6, 0xc9, 0x0b, 0x78, 0x94, 0xe8, + 0x77, 0xe7, 0x05, 0x99, 0x85, 0x3e, 0x15, 0x34, 0x86, 0x4a, 0xcf, 0x2c, 0xf9, 0x23, 0x91, 0x0c, + 0x04, 0x95, 0xac, 0x8a, 0xea, 0xa8, 0x51, 0x72, 0xf1, 0x7c, 0x69, 0x1b, 0x8f, 0x4b, 0x7b, 0x2f, + 0x8c, 0xe4, 0xd5, 0xc8, 0xc7, 0x01, 0x8f, 0x49, 0x1e, 0xa8, 0x8f, 0x26, 0x5c, 0x5e, 0x13, 0x39, + 0x4d, 0x19, 0xe0, 0x63, 0x16, 0x78, 0x45, 0x15, 0xe0, 0x51, 0xc9, 0x2a, 0x37, 0xc8, 0x34, 0x43, + 0x0a, 0x83, 0x54, 0x44, 0x01, 0x83, 0xea, 0xaf, 0xfa, 0xef, 0x46, 0xb9, 0xbd, 0x8d, 0xb5, 0x0b, + 0x2b, 0x9a, 0x0f, 0x70, 0x65, 0x3c, 0xe2, 0x51, 0xe2, 0x9e, 0xaa, 0xcf, 0xde, 0x96, 0xf6, 0xbf, + 0x29, 0x8d, 0x87, 0x5d, 0xe7, 0xd3, 0xed, 0xdc, 0x3f, 0xd9, 0xfb, 0x3f, 0x23, 0x50, 0x41, 0xe0, + 0x95, 0x42, 0x0a, 0xfd, 0xcc, 0xda, 0x2d, 0xde, 0xcd, 0x6c, 0xf4, 0x3a, 0xb3, 0x91, 0xd3, 0x33, + 0xff, 0x9e, 0xe8, 0x3d, 0x9e, 0x4b, 0x45, 0x78, 0x68, 0x16, 0xd2, 0x6c, 0xf0, 0x6c, 0xd6, 0x72, + 0x7b, 0x07, 0x7f, 0xbb, 0x57, 0xac, 0xb7, 0xe3, 0xfe, 0x51, 0x74, 0x5e, 0x6e, 0x71, 0xcf, 0xe6, + 0x2b, 0x0b, 0x2d, 0x56, 0x16, 0x7a, 0x5e, 0x59, 0xe8, 0x76, 0x6d, 0x19, 0x8b, 0xb5, 0x65, 0x3c, + 0xac, 0x2d, 0xe3, 0xe2, 0xe0, 0x2b, 0xe8, 0x90, 0x02, 0x44, 0x41, 0x53, 0xb7, 0x1a, 0x70, 0xc1, + 0xc8, 0xb8, 0x43, 0x26, 0x9b, 0x7e, 0x33, 0x6c, 0xbf, 0x90, 0x35, 0xd1, 0x79, 0x0f, 0x00, 0x00, + 0xff, 0xff, 0x3c, 0x5f, 0xca, 0xac, 0xfd, 0x01, 0x00, 0x00, } +func (this *Params) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*Params) + if !ok { + that2, ok := that.(Params) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if !this.BurnRate.Equal(that1.BurnRate) { + return false + } + if len(this.GasPrices) != len(that1.GasPrices) { + return false + } + for i := range this.GasPrices { + if !this.GasPrices[i].Equal(&that1.GasPrices[i]) { + return false + } + } + return true +} func (m *Params) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -152,6 +204,30 @@ func (m *Params) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if len(m.GasPrices) > 0 { + for iNdEx := len(m.GasPrices) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.GasPrices[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + } + { + size := m.BurnRate.Size() + i -= size + if _, err := m.BurnRate.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa return len(dAtA) - i, nil } @@ -205,6 +281,14 @@ func (m *Params) Size() (n int) { } var l int _ = l + l = m.BurnRate.Size() + n += 1 + l + sovGenesis(uint64(l)) + if len(m.GasPrices) > 0 { + for _, e := range m.GasPrices { + l = e.Size() + n += 1 + l + sovGenesis(uint64(l)) + } + } return n } @@ -254,6 +338,74 @@ func (m *Params) Unmarshal(dAtA []byte) error { return fmt.Errorf("proto: Params: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field BurnRate", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.BurnRate.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field GasPrices", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.GasPrices = append(m.GasPrices, types.DecCoin{}) + if err := m.GasPrices[len(m.GasPrices)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipGenesis(dAtA[iNdEx:]) diff --git a/x/tax2gas/types/keys.go b/x/tax2gas/types/keys.go index ac537a231..795af6f75 100644 --- a/x/tax2gas/types/keys.go +++ b/x/tax2gas/types/keys.go @@ -6,7 +6,17 @@ const ( StoreKey = ModuleName RouterKey = ModuleName + + ConsumedGasFee = "consumedGasFee" + + TaxGas = "taxGas" + + FeeDenom = "feeDenom" ) // Key defines the store key for tax2gas. -var Key = []byte{0x01} +var ( + Key = []byte{0x01} + + ParamsKey = []byte{0x30} +) diff --git a/x/tax2gas/types/params.go b/x/tax2gas/types/params.go index 9d11dd3f4..30a40e3c6 100644 --- a/x/tax2gas/types/params.go +++ b/x/tax2gas/types/params.go @@ -1,6 +1,8 @@ package types import ( + "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" ) @@ -20,7 +22,34 @@ func NewParams() Params { // DefaultParams are the default tax2gas module parameters. func DefaultParams() Params { - return Params{} + return Params{ + BurnRate: sdk.NewDecFromIntWithPrec(math.NewInt(1), 2), + GasPrices: sdk.NewDecCoins( + sdk.NewDecCoinFromDec("uluna", sdk.NewDecWithPrec(28325, 3)), + sdk.NewDecCoinFromDec("usdr", sdk.NewDecWithPrec(52469, 5)), + sdk.NewDecCoinFromDec("uusd", sdk.NewDecWithPrec(75, 2)), + sdk.NewDecCoinFromDec("ukrw", sdk.NewDecWithPrec(850, 0)), + sdk.NewDecCoinFromDec("umnt", sdk.NewDecWithPrec(2142855, 3)), + sdk.NewDecCoinFromDec("ueur", sdk.NewDecWithPrec(625, 3)), + sdk.NewDecCoinFromDec("ucny", sdk.NewDecWithPrec(49, 1)), + sdk.NewDecCoinFromDec("ujpy", sdk.NewDecWithPrec(8185, 2)), + sdk.NewDecCoinFromDec("ugbp", sdk.NewDecWithPrec(55, 2)), + sdk.NewDecCoinFromDec("uinr", sdk.NewDecWithPrec(544, 1)), + sdk.NewDecCoinFromDec("ucad", sdk.NewDecWithPrec(95, 2)), + sdk.NewDecCoinFromDec("uchf", sdk.NewDecWithPrec(7, 1)), + sdk.NewDecCoinFromDec("uaud", sdk.NewDecWithPrec(95, 2)), + sdk.NewDecCoinFromDec("usgd", sdk.NewDec(1)), + sdk.NewDecCoinFromDec("uthb", sdk.NewDecWithPrec(231, 1)), + sdk.NewDecCoinFromDec("usek", sdk.NewDecWithPrec(625, 2)), + sdk.NewDecCoinFromDec("unok", sdk.NewDecWithPrec(625, 2)), + sdk.NewDecCoinFromDec("udkk", sdk.NewDecWithPrec(45, 1)), + sdk.NewDecCoinFromDec("uidr", sdk.NewDecWithPrec(10900, 0)), + sdk.NewDecCoinFromDec("uphp", sdk.NewDecWithPrec(38, 0)), + sdk.NewDecCoinFromDec("uhkd", sdk.NewDecWithPrec(585, 2)), + sdk.NewDecCoinFromDec("umyr", sdk.NewDecWithPrec(3, 0)), + sdk.NewDecCoinFromDec("utwd", sdk.NewDecWithPrec(20, 0)), + ), + } } // Validate validates params. diff --git a/x/tax2gas/types/query.pb.go b/x/tax2gas/types/query.pb.go index 8ebbce812..9597dd1a5 100644 --- a/x/tax2gas/types/query.pb.go +++ b/x/tax2gas/types/query.pb.go @@ -30,21 +30,21 @@ var _ = math.Inf const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package // =============================== Params -type ParamsRequest struct { +type QueryParamsRequest struct { } -func (m *ParamsRequest) Reset() { *m = ParamsRequest{} } -func (m *ParamsRequest) String() string { return proto.CompactTextString(m) } -func (*ParamsRequest) ProtoMessage() {} -func (*ParamsRequest) Descriptor() ([]byte, []int) { +func (m *QueryParamsRequest) Reset() { *m = QueryParamsRequest{} } +func (m *QueryParamsRequest) String() string { return proto.CompactTextString(m) } +func (*QueryParamsRequest) ProtoMessage() {} +func (*QueryParamsRequest) Descriptor() ([]byte, []int) { return fileDescriptor_bfce3f3a760d419d, []int{0} } -func (m *ParamsRequest) XXX_Unmarshal(b []byte) error { +func (m *QueryParamsRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) } -func (m *ParamsRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { +func (m *QueryParamsRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { if deterministic { - return xxx_messageInfo_ParamsRequest.Marshal(b, m, deterministic) + return xxx_messageInfo_QueryParamsRequest.Marshal(b, m, deterministic) } else { b = b[:cap(b)] n, err := m.MarshalToSizedBuffer(b) @@ -54,34 +54,34 @@ func (m *ParamsRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error return b[:n], nil } } -func (m *ParamsRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_ParamsRequest.Merge(m, src) +func (m *QueryParamsRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryParamsRequest.Merge(m, src) } -func (m *ParamsRequest) XXX_Size() int { +func (m *QueryParamsRequest) XXX_Size() int { return m.Size() } -func (m *ParamsRequest) XXX_DiscardUnknown() { - xxx_messageInfo_ParamsRequest.DiscardUnknown(m) +func (m *QueryParamsRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryParamsRequest.DiscardUnknown(m) } -var xxx_messageInfo_ParamsRequest proto.InternalMessageInfo +var xxx_messageInfo_QueryParamsRequest proto.InternalMessageInfo -type ParamsResponse struct { +type QueryParamsResponse struct { Params Params `protobuf:"bytes,1,opt,name=params,proto3" json:"params"` } -func (m *ParamsResponse) Reset() { *m = ParamsResponse{} } -func (m *ParamsResponse) String() string { return proto.CompactTextString(m) } -func (*ParamsResponse) ProtoMessage() {} -func (*ParamsResponse) Descriptor() ([]byte, []int) { +func (m *QueryParamsResponse) Reset() { *m = QueryParamsResponse{} } +func (m *QueryParamsResponse) String() string { return proto.CompactTextString(m) } +func (*QueryParamsResponse) ProtoMessage() {} +func (*QueryParamsResponse) Descriptor() ([]byte, []int) { return fileDescriptor_bfce3f3a760d419d, []int{1} } -func (m *ParamsResponse) XXX_Unmarshal(b []byte) error { +func (m *QueryParamsResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) } -func (m *ParamsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { +func (m *QueryParamsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { if deterministic { - return xxx_messageInfo_ParamsResponse.Marshal(b, m, deterministic) + return xxx_messageInfo_QueryParamsResponse.Marshal(b, m, deterministic) } else { b = b[:cap(b)] n, err := m.MarshalToSizedBuffer(b) @@ -91,19 +91,19 @@ func (m *ParamsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, erro return b[:n], nil } } -func (m *ParamsResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_ParamsResponse.Merge(m, src) +func (m *QueryParamsResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryParamsResponse.Merge(m, src) } -func (m *ParamsResponse) XXX_Size() int { +func (m *QueryParamsResponse) XXX_Size() int { return m.Size() } -func (m *ParamsResponse) XXX_DiscardUnknown() { - xxx_messageInfo_ParamsResponse.DiscardUnknown(m) +func (m *QueryParamsResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryParamsResponse.DiscardUnknown(m) } -var xxx_messageInfo_ParamsResponse proto.InternalMessageInfo +var xxx_messageInfo_QueryParamsResponse proto.InternalMessageInfo -func (m *ParamsResponse) GetParams() Params { +func (m *QueryParamsResponse) GetParams() Params { if m != nil { return m.Params } @@ -111,33 +111,33 @@ func (m *ParamsResponse) GetParams() Params { } func init() { - proto.RegisterType((*ParamsRequest)(nil), "terra.tax2gas.v1beta1.ParamsRequest") - proto.RegisterType((*ParamsResponse)(nil), "terra.tax2gas.v1beta1.ParamsResponse") + proto.RegisterType((*QueryParamsRequest)(nil), "terra.tax2gas.v1beta1.QueryParamsRequest") + proto.RegisterType((*QueryParamsResponse)(nil), "terra.tax2gas.v1beta1.QueryParamsResponse") } func init() { proto.RegisterFile("terra/tax2gas/v1beta1/query.proto", fileDescriptor_bfce3f3a760d419d) } var fileDescriptor_bfce3f3a760d419d = []byte{ - // 292 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x52, 0x2c, 0x49, 0x2d, 0x2a, - 0x4a, 0xd4, 0x2f, 0x49, 0xac, 0x30, 0x4a, 0x4f, 0x2c, 0xd6, 0x2f, 0x33, 0x4c, 0x4a, 0x2d, 0x49, - 0x34, 0xd4, 0x2f, 0x2c, 0x4d, 0x2d, 0xaa, 0xd4, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x12, 0x05, - 0x2b, 0xd1, 0x83, 0x2a, 0xd1, 0x83, 0x2a, 0x91, 0x12, 0x49, 0xcf, 0x4f, 0xcf, 0x07, 0xab, 0xd0, - 0x07, 0xb1, 0x20, 0x8a, 0xa5, 0x64, 0xd2, 0xf3, 0xf3, 0xd3, 0x73, 0x52, 0xf5, 0x13, 0x0b, 0x32, - 0xf5, 0x13, 0xf3, 0xf2, 0xf2, 0x4b, 0x12, 0x4b, 0x32, 0xf3, 0xf3, 0x8a, 0xa1, 0xb2, 0xca, 0xd8, - 0x6d, 0x4b, 0x4f, 0xcd, 0x4b, 0x2d, 0xce, 0x84, 0x2a, 0x52, 0xe2, 0xe7, 0xe2, 0x0d, 0x48, 0x2c, - 0x4a, 0xcc, 0x2d, 0x0e, 0x4a, 0x2d, 0x2c, 0x4d, 0x2d, 0x2e, 0x51, 0xf2, 0xe5, 0xe2, 0x83, 0x09, - 0x14, 0x17, 0xe4, 0xe7, 0x15, 0xa7, 0x0a, 0x59, 0x73, 0xb1, 0x15, 0x80, 0x45, 0x24, 0x18, 0x15, - 0x18, 0x35, 0xb8, 0x8d, 0x64, 0xf5, 0xb0, 0xba, 0x51, 0x0f, 0xa2, 0xcd, 0x89, 0xe5, 0xc4, 0x3d, - 0x79, 0x86, 0x20, 0xa8, 0x16, 0xa3, 0x5a, 0x2e, 0xd6, 0x40, 0x90, 0xf7, 0x84, 0x4a, 0xb8, 0xd8, - 0x20, 0x0a, 0x84, 0x54, 0xf0, 0xea, 0x87, 0xba, 0x43, 0x4a, 0x95, 0x80, 0x2a, 0x88, 0xe3, 0x94, - 0x64, 0x9b, 0x2e, 0x3f, 0x99, 0xcc, 0x24, 0x2e, 0x24, 0xaa, 0x8f, 0xea, 0x5b, 0xa8, 0x63, 0xbc, - 0x4e, 0x3c, 0x92, 0x63, 0xbc, 0xf0, 0x48, 0x8e, 0xf1, 0xc1, 0x23, 0x39, 0xc6, 0x09, 0x8f, 0xe5, - 0x18, 0x2e, 0x3c, 0x96, 0x63, 0xb8, 0xf1, 0x58, 0x8e, 0x21, 0xca, 0x20, 0x3d, 0xb3, 0x24, 0xa3, - 0x34, 0x49, 0x2f, 0x39, 0x3f, 0x57, 0x3f, 0x39, 0x27, 0xb1, 0xb8, 0x38, 0x33, 0x59, 0x17, 0x62, - 0x44, 0x72, 0x7e, 0x51, 0xaa, 0x7e, 0x99, 0xb1, 0x7e, 0x05, 0xdc, 0xb0, 0x92, 0xca, 0x82, 0xd4, - 0xe2, 0x24, 0x36, 0x70, 0x88, 0x19, 0x03, 0x02, 0x00, 0x00, 0xff, 0xff, 0xb6, 0x70, 0x1a, 0xdb, - 0xc6, 0x01, 0x00, 0x00, + // 294 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x90, 0x31, 0x4b, 0xc3, 0x40, + 0x14, 0xc7, 0x73, 0xa2, 0x19, 0xce, 0xed, 0x6c, 0x51, 0x82, 0x3d, 0x35, 0x2e, 0x2a, 0x78, 0x67, + 0xd3, 0xd1, 0xcd, 0xd1, 0x49, 0x33, 0xba, 0x5d, 0xc2, 0x71, 0x06, 0xda, 0xbc, 0xf4, 0xee, 0x52, + 0xda, 0xc5, 0xc1, 0xc5, 0x55, 0xf0, 0x4b, 0x75, 0x2c, 0xb8, 0x38, 0x89, 0x24, 0x7e, 0x10, 0x69, + 0x72, 0x08, 0xc5, 0x0a, 0xdd, 0x8e, 0x77, 0xbf, 0xf7, 0x7f, 0x3f, 0xfe, 0xf8, 0xc4, 0x4a, 0xad, + 0x05, 0xb7, 0x62, 0x1a, 0x29, 0x61, 0xf8, 0xa4, 0x9f, 0x48, 0x2b, 0xfa, 0x7c, 0x5c, 0x4a, 0x3d, + 0x63, 0x85, 0x06, 0x0b, 0xa4, 0xdb, 0x20, 0xcc, 0x21, 0xcc, 0x21, 0x41, 0x47, 0x81, 0x82, 0x86, + 0xe0, 0xcb, 0x57, 0x0b, 0x07, 0x87, 0x0a, 0x40, 0x0d, 0x25, 0x17, 0x45, 0xc6, 0x45, 0x9e, 0x83, + 0x15, 0x36, 0x83, 0xdc, 0xb8, 0xdf, 0xd3, 0xf5, 0xd7, 0x94, 0xcc, 0xa5, 0xc9, 0x1c, 0x14, 0x76, + 0x30, 0xb9, 0x5f, 0x9e, 0xbf, 0x13, 0x5a, 0x8c, 0x4c, 0x2c, 0xc7, 0xa5, 0x34, 0x36, 0x8c, 0xf1, + 0xde, 0xca, 0xd4, 0x14, 0x90, 0x1b, 0x49, 0xae, 0xb1, 0x5f, 0x34, 0x93, 0x03, 0x74, 0x8c, 0xce, + 0x76, 0xa3, 0x1e, 0x5b, 0x6b, 0xcb, 0xda, 0xb5, 0x9b, 0xed, 0xf9, 0xe7, 0x91, 0x17, 0xbb, 0x95, + 0xe8, 0x05, 0xe1, 0x9d, 0x26, 0x94, 0x3c, 0x61, 0xbf, 0x25, 0xc8, 0xf9, 0x3f, 0x01, 0x7f, 0x95, + 0x82, 0x8b, 0x4d, 0xd0, 0xd6, 0x33, 0xec, 0x3d, 0xbf, 0x7f, 0xbf, 0x6d, 0xed, 0x93, 0x2e, 0x5f, + 0xad, 0xc0, 0x79, 0xdd, 0xce, 0x2b, 0x8a, 0x16, 0x15, 0x45, 0x5f, 0x15, 0x45, 0xaf, 0x35, 0xf5, + 0x16, 0x35, 0xf5, 0x3e, 0x6a, 0xea, 0x3d, 0x5c, 0xa9, 0xcc, 0x3e, 0x96, 0x09, 0x4b, 0x61, 0xc4, + 0xd3, 0xa1, 0x30, 0x26, 0x4b, 0x2f, 0xdb, 0x88, 0x14, 0xb4, 0xe4, 0x93, 0x01, 0x9f, 0xfe, 0x86, + 0xd9, 0x59, 0x21, 0x4d, 0xe2, 0x37, 0x35, 0x0e, 0x7e, 0x02, 0x00, 0x00, 0xff, 0xff, 0x08, 0x41, + 0xa4, 0x16, 0xdb, 0x01, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -152,7 +152,7 @@ const _ = grpc.SupportPackageIsVersion4 // // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. type QueryClient interface { - Params(ctx context.Context, in *ParamsRequest, opts ...grpc.CallOption) (*ParamsResponse, error) + Params(ctx context.Context, in *QueryParamsRequest, opts ...grpc.CallOption) (*QueryParamsResponse, error) } type queryClient struct { @@ -163,8 +163,8 @@ func NewQueryClient(cc grpc1.ClientConn) QueryClient { return &queryClient{cc} } -func (c *queryClient) Params(ctx context.Context, in *ParamsRequest, opts ...grpc.CallOption) (*ParamsResponse, error) { - out := new(ParamsResponse) +func (c *queryClient) Params(ctx context.Context, in *QueryParamsRequest, opts ...grpc.CallOption) (*QueryParamsResponse, error) { + out := new(QueryParamsResponse) err := c.cc.Invoke(ctx, "/terra.tax2gas.v1beta1.Query/Params", in, out, opts...) if err != nil { return nil, err @@ -174,14 +174,14 @@ func (c *queryClient) Params(ctx context.Context, in *ParamsRequest, opts ...grp // QueryServer is the server API for Query service. type QueryServer interface { - Params(context.Context, *ParamsRequest) (*ParamsResponse, error) + Params(context.Context, *QueryParamsRequest) (*QueryParamsResponse, error) } // UnimplementedQueryServer can be embedded to have forward compatible implementations. type UnimplementedQueryServer struct { } -func (*UnimplementedQueryServer) Params(ctx context.Context, req *ParamsRequest) (*ParamsResponse, error) { +func (*UnimplementedQueryServer) Params(ctx context.Context, req *QueryParamsRequest) (*QueryParamsResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method Params not implemented") } @@ -190,7 +190,7 @@ func RegisterQueryServer(s grpc1.Server, srv QueryServer) { } func _Query_Params_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(ParamsRequest) + in := new(QueryParamsRequest) if err := dec(in); err != nil { return nil, err } @@ -202,7 +202,7 @@ func _Query_Params_Handler(srv interface{}, ctx context.Context, dec func(interf FullMethod: "/terra.tax2gas.v1beta1.Query/Params", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(QueryServer).Params(ctx, req.(*ParamsRequest)) + return srv.(QueryServer).Params(ctx, req.(*QueryParamsRequest)) } return interceptor(ctx, in, info, handler) } @@ -220,7 +220,7 @@ var _Query_serviceDesc = grpc.ServiceDesc{ Metadata: "terra/tax2gas/v1beta1/query.proto", } -func (m *ParamsRequest) Marshal() (dAtA []byte, err error) { +func (m *QueryParamsRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalToSizedBuffer(dAtA[:size]) @@ -230,12 +230,12 @@ func (m *ParamsRequest) Marshal() (dAtA []byte, err error) { return dAtA[:n], nil } -func (m *ParamsRequest) MarshalTo(dAtA []byte) (int, error) { +func (m *QueryParamsRequest) MarshalTo(dAtA []byte) (int, error) { size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *ParamsRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { +func (m *QueryParamsRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) _ = i var l int @@ -243,7 +243,7 @@ func (m *ParamsRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } -func (m *ParamsResponse) Marshal() (dAtA []byte, err error) { +func (m *QueryParamsResponse) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalToSizedBuffer(dAtA[:size]) @@ -253,12 +253,12 @@ func (m *ParamsResponse) Marshal() (dAtA []byte, err error) { return dAtA[:n], nil } -func (m *ParamsResponse) MarshalTo(dAtA []byte) (int, error) { +func (m *QueryParamsResponse) MarshalTo(dAtA []byte) (int, error) { size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *ParamsResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { +func (m *QueryParamsResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) _ = i var l int @@ -287,7 +287,7 @@ func encodeVarintQuery(dAtA []byte, offset int, v uint64) int { dAtA[offset] = uint8(v) return base } -func (m *ParamsRequest) Size() (n int) { +func (m *QueryParamsRequest) Size() (n int) { if m == nil { return 0 } @@ -296,7 +296,7 @@ func (m *ParamsRequest) Size() (n int) { return n } -func (m *ParamsResponse) Size() (n int) { +func (m *QueryParamsResponse) Size() (n int) { if m == nil { return 0 } @@ -313,7 +313,7 @@ func sovQuery(x uint64) (n int) { func sozQuery(x uint64) (n int) { return sovQuery(uint64((x << 1) ^ uint64((int64(x) >> 63)))) } -func (m *ParamsRequest) Unmarshal(dAtA []byte) error { +func (m *QueryParamsRequest) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -336,10 +336,10 @@ func (m *ParamsRequest) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: ParamsRequest: wiretype end group for non-group") + return fmt.Errorf("proto: QueryParamsRequest: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: ParamsRequest: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: QueryParamsRequest: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { default: @@ -363,7 +363,7 @@ func (m *ParamsRequest) Unmarshal(dAtA []byte) error { } return nil } -func (m *ParamsResponse) Unmarshal(dAtA []byte) error { +func (m *QueryParamsResponse) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -386,10 +386,10 @@ func (m *ParamsResponse) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: ParamsResponse: wiretype end group for non-group") + return fmt.Errorf("proto: QueryParamsResponse: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: ParamsResponse: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: QueryParamsResponse: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: diff --git a/x/tax2gas/types/query.pb.gw.go b/x/tax2gas/types/query.pb.gw.go index 3214847a9..27f6ee6cf 100644 --- a/x/tax2gas/types/query.pb.gw.go +++ b/x/tax2gas/types/query.pb.gw.go @@ -34,7 +34,7 @@ var _ = descriptor.ForMessage var _ = metadata.Join func request_Query_Params_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq ParamsRequest + var protoReq QueryParamsRequest var metadata runtime.ServerMetadata msg, err := client.Params(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) @@ -43,7 +43,7 @@ func request_Query_Params_0(ctx context.Context, marshaler runtime.Marshaler, cl } func local_request_Query_Params_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq ParamsRequest + var protoReq QueryParamsRequest var metadata runtime.ServerMetadata msg, err := server.Params(ctx, &protoReq) diff --git a/x/wasm/keeper/testdata/test.wasm b/x/wasm/keeper/testdata/test.wasm new file mode 100644 index 000000000..8194957c7 Binary files /dev/null and b/x/wasm/keeper/testdata/test.wasm differ