diff --git a/app/app.go b/app/app.go index 73a944da7..de408c9b5 100644 --- a/app/app.go +++ b/app/app.go @@ -55,6 +55,7 @@ import ( v7 "github.com/classic-terra/core/v3/app/upgrades/v7" v7_1 "github.com/classic-terra/core/v3/app/upgrades/v7_1" v8 "github.com/classic-terra/core/v3/app/upgrades/v8" + v8_1 "github.com/classic-terra/core/v3/app/upgrades/v8_1" customante "github.com/classic-terra/core/v3/custom/auth/ante" custompost "github.com/classic-terra/core/v3/custom/auth/post" @@ -75,7 +76,18 @@ var ( DefaultNodeHome string // Upgrades defines upgrades to be applied to the network - Upgrades = []upgrades.Upgrade{v2.Upgrade, v3.Upgrade, v4.Upgrade, v5.Upgrade, v6.Upgrade, v6_1.Upgrade, v7.Upgrade, v7_1.Upgrade, v8.Upgrade} + Upgrades = []upgrades.Upgrade{ + v2.Upgrade, + v3.Upgrade, + v4.Upgrade, + v5.Upgrade, + v6.Upgrade, + v6_1.Upgrade, + v7.Upgrade, + v7_1.Upgrade, + v8.Upgrade, + v8_1.Upgrade, + } // Forks defines forks to be applied to the network Forks = []upgrades.Fork{} @@ -228,6 +240,7 @@ func NewTerraApp( TXCounterStoreKey: app.GetKey(wasmtypes.StoreKey), DyncommKeeper: app.DyncommKeeper, StakingKeeper: app.StakingKeeper, + Tax2Gaskeeper: app.Tax2gasKeeper, Cdc: app.appCodec, }, ) @@ -237,7 +250,12 @@ func NewTerraApp( postHandler, err := custompost.NewPostHandler( custompost.HandlerOptions{ - DyncommKeeper: app.DyncommKeeper, + AccountKeeper: app.AccountKeeper, + BankKeeper: app.BankKeeper, + FeegrantKeeper: app.FeeGrantKeeper, + 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..8f7ffee7e 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], + authtypes.NewModuleAddress(govtypes.ModuleName).String(), + ) + // Create IBC Keeper appKeepers.IBCKeeper = ibckeeper.NewKeeper( appCodec, @@ -390,6 +399,7 @@ func NewAppKeepers( appKeepers.BankKeeper, appKeepers.TreasuryKeeper, appKeepers.AccountKeeper, + appKeepers.Tax2gasKeeper, appCodec, appKeepers.TransferKeeper, ) diff --git a/app/legacy/pubkey_replacement.go b/app/legacy/pubkey_replacement.go index be598d2a0..caef40dfb 100644 --- a/app/legacy/pubkey_replacement.go +++ b/app/legacy/pubkey_replacement.go @@ -46,7 +46,6 @@ func loadKeydataFromFile(clientCtx client.Context, replacementrJSON string, genD var replacementKeys replacementConfigs err = json.Unmarshal(jsonReplacementBlob, &replacementKeys) - if err != nil { log.Fatal(errors.Wrap(err, "Could not unmarshal replacement keys ")) } @@ -112,7 +111,6 @@ func loadKeydataFromFile(clientCtx client.Context, replacementrJSON string, genD state[slashing.ModuleName] = clientCtx.Codec.MustMarshalJSON(&slashingGenesis) genDoc.AppState, err = json.Marshal(state) - if err != nil { log.Fatal("Could not marshal App State") } 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/app/upgrades/v8_1/constants.go b/app/upgrades/v8_1/constants.go new file mode 100644 index 000000000..f692af908 --- /dev/null +++ b/app/upgrades/v8_1/constants.go @@ -0,0 +1,13 @@ +//nolint:revive +package v8_1 + +import ( + "github.com/classic-terra/core/v3/app/upgrades" +) + +const UpgradeName = "v8_1" + +var Upgrade = upgrades.Upgrade{ + UpgradeName: UpgradeName, + CreateUpgradeHandler: CreateV81UpgradeHandler, +} diff --git a/app/upgrades/v8_1/upgrades.go b/app/upgrades/v8_1/upgrades.go new file mode 100644 index 000000000..1a3abf159 --- /dev/null +++ b/app/upgrades/v8_1/upgrades.go @@ -0,0 +1,24 @@ +//nolint:revive +package v8_1 + +import ( + "github.com/classic-terra/core/v3/app/keepers" + "github.com/classic-terra/core/v3/app/upgrades" + treasurytypes "github.com/classic-terra/core/v3/x/treasury/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/module" + upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" +) + +func CreateV81UpgradeHandler( + mm *module.Manager, + cfg module.Configurator, + _ upgrades.BaseAppParamManager, + keepers *keepers.AppKeepers, +) upgradetypes.UpgradeHandler { + return func(ctx sdk.Context, _ upgradetypes.Plan, fromVM module.VersionMap) (module.VersionMap, error) { + // set default oracle split + keepers.TreasuryKeeper.SetOracleSplitRate(ctx, treasurytypes.DefaultOracleSplit) + return mm.RunMigrations(ctx, cfg, fromVM) + } +} diff --git a/contrib/updates/Dockerfile.old b/contrib/updates/Dockerfile.old index 95defca46..5e4e6cd11 100644 --- a/contrib/updates/Dockerfile.old +++ b/contrib/updates/Dockerfile.old @@ -52,8 +52,8 @@ RUN --mount=type=cache,target=/root/.cache/go-build \ # Cosmwasm - Download correct libwasmvm version and verify checksum RUN set -eux &&\ - WASMVM_VERSION=$(go list -m github.com/CosmWasm/wasmvm | cut -d ' ' -f 5) && \ - WASMVM_DOWNLOADS="https://github.com/classic-terra/wasmvm/releases/download/${WASMVM_VERSION}"; \ + WASMVM_VERSION=$(go list -m github.com/CosmWasm/wasmvm | cut -d ' ' -f 2) && \ + WASMVM_DOWNLOADS="https://github.com/CosmWasm/wasmvm/releases/download/${WASMVM_VERSION}"; \ wget ${WASMVM_DOWNLOADS}/checksums.txt -O /tmp/checksums.txt; \ if [ ${BUILDPLATFORM} = "linux/amd64" ]; then \ WASMVM_URL="${WASMVM_DOWNLOADS}/libwasmvm_muslc.x86_64.a"; \ diff --git a/contrib/updates/docker-compose.yml b/contrib/updates/docker-compose.yml index 9a8a9d5ed..57cef82af 100644 --- a/contrib/updates/docker-compose.yml +++ b/contrib/updates/docker-compose.yml @@ -139,4 +139,4 @@ networks: driver: default config: - - subnet: 192.168.10.0/16 \ No newline at end of file + subnet: 192.168.10.0/24 \ No newline at end of file diff --git a/contrib/updates/prepare_cosmovisor.sh b/contrib/updates/prepare_cosmovisor.sh index b55fad1be..703be14a9 100644 --- a/contrib/updates/prepare_cosmovisor.sh +++ b/contrib/updates/prepare_cosmovisor.sh @@ -5,7 +5,7 @@ # These fields should be fetched automatically in the future # Need to do more upgrade to see upgrade patterns -OLD_VERSION=v2.4.2 +OLD_VERSION=v3.0.3 # this command will retrieve the folder with the largest number in format v SOFTWARE_UPGRADE_NAME=$(ls -d -- ./app/upgrades/v* | sort -Vr | head -n 1 | xargs basename) BUILDDIR=$1 diff --git a/contrib/updates/upgrade-test.sh b/contrib/updates/upgrade-test.sh old mode 100644 new mode 100755 diff --git a/custom/auth/ante/ante.go b/custom/auth/ante/ante.go index 7dabfce5a..ddfcde150 100644 --- a/custom/auth/ante/ante.go +++ b/custom/auth/ante/ante.go @@ -12,6 +12,9 @@ import ( dyncommante "github.com/classic-terra/core/v3/x/dyncomm/ante" 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" + tax2gastypes "github.com/classic-terra/core/v3/x/tax2gas/types" "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" @@ -26,7 +29,7 @@ type HandlerOptions struct { AccountKeeper ante.AccountKeeper BankKeeper BankKeeper ExtensionOptionChecker ante.ExtensionOptionChecker - FeegrantKeeper ante.FeegrantKeeper + FeegrantKeeper tax2gastypes.FeegrantKeeper OracleKeeper OracleKeeper TreasuryKeeper TreasuryKeeper SignModeHandler signing.SignModeHandler @@ -40,6 +43,7 @@ type HandlerOptions struct { TXCounterStoreKey storetypes.StoreKey DyncommKeeper dyncommkeeper.Keeper StakingKeeper *stakingkeeper.Keeper + Tax2Gaskeeper tax2gaskeeper.Keeper Cdc codec.BinaryCodec } @@ -88,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), - 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..727857853 100644 --- a/custom/auth/ante/expected_keeper.go +++ b/custom/auth/ante/expected_keeper.go @@ -16,6 +16,7 @@ type TreasuryKeeper interface { HasBurnTaxExemptionAddress(ctx sdk.Context, addresses ...string) bool HasBurnTaxExemptionContract(ctx sdk.Context, address string) bool GetMinInitialDepositRatio(ctx sdk.Context) sdk.Dec + GetOracleSplitRate(ctx sdk.Context) sdk.Dec } // OracleKeeper for feeder validation @@ -25,15 +26,19 @@ type OracleKeeper interface { // BankKeeper defines the contract needed for supply related APIs (noalias) type BankKeeper interface { + GetBalance(ctx sdk.Context, addr sdk.AccAddress, denom string) sdk.Coin 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 + SendCoinsFromModuleToAccount(ctx sdk.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins) error } type DistrKeeper interface { FundCommunityPool(ctx sdk.Context, amount sdk.Coins, sender sdk.AccAddress) error GetFeePool(ctx sdk.Context) distributiontypes.FeePool + GetCommunityTax(ctx sdk.Context) math.LegacyDec + SetFeePool(ctx sdk.Context, feePool distributiontypes.FeePool) } type GovKeeper interface { diff --git a/custom/auth/ante/fee.go b/custom/auth/ante/fee.go deleted file mode 100644 index 44acc1f4b..000000000 --- a/custom/auth/ante/fee.go +++ /dev/null @@ -1,211 +0,0 @@ -package ante - -import ( - "fmt" - "math" - - 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" - "github.com/cosmos/cosmos-sdk/x/auth/types" -) - -// FeeDecorator deducts fees from the first signer of the tx -// If the first signer does not have the funds to pay for the fees, return with InsufficientFunds error -// Call next AnteHandler if fees successfully deducted -// CONTRACT: Tx must implement FeeTx interface to use DeductFeeDecorator -type FeeDecorator struct { - accountKeeper ante.AccountKeeper - bankKeeper BankKeeper - feegrantKeeper ante.FeegrantKeeper - treasuryKeeper TreasuryKeeper -} - -func NewFeeDecorator(ak ante.AccountKeeper, bk BankKeeper, fk ante.FeegrantKeeper, tk TreasuryKeeper) FeeDecorator { - return FeeDecorator{ - accountKeeper: ak, - bankKeeper: bk, - feegrantKeeper: fk, - treasuryKeeper: tk, - } -} - -func (fd FeeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (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") - } - - var ( - priority int64 - err error - ) - - msgs := feeTx.GetMsgs() - // Compute taxes - taxes := FilterMsgAndComputeTax(ctx, fd.treasuryKeeper, msgs...) - - if !simulate { - priority, err = fd.checkTxFee(ctx, tx, taxes) - if err != nil { - return ctx, err - } - } - - if err := fd.checkDeductFee(ctx, feeTx, taxes, simulate); err != nil { - return ctx, err - } - - newCtx := ctx.WithPriority(priority) - - return next(newCtx, tx, simulate) -} - -func (fd FeeDecorator) checkDeductFee(ctx sdk.Context, feeTx sdk.FeeTx, taxes sdk.Coins, simulate bool) error { - if addr := fd.accountKeeper.GetModuleAddress(types.FeeCollectorName); addr == nil { - return fmt.Errorf("fee collector module account (%s) has not been set", types.FeeCollectorName) - } - - fee := feeTx.GetFee() - feePayer := feeTx.FeePayer() - feeGranter := feeTx.FeeGranter() - deductFeesFrom := feePayer - - // 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") - } else if !feeGranter.Equals(feePayer) { - err := fd.feegrantKeeper.UseGrantedFees(ctx, feeGranter, feePayer, fee, feeTx.GetMsgs()) - if err != nil { - return errorsmod.Wrapf(err, "%s does not not allow to pay fees for %s", feeGranter, feePayer) - } - } - - deductFeesFrom = feeGranter - } - - deductFeesFromAcc := fd.accountKeeper.GetAccount(ctx, deductFeesFrom) - if deductFeesFromAcc == nil { - 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 err != nil { - return err - } - - if !taxes.IsZero() && !simulate { - err := fd.BurnTaxSplit(ctx, taxes) - if err != nil { - return err - } - - // Record tax proceeds - fd.treasuryKeeper.RecordEpochTaxProceeds(ctx, taxes) - } - } - - events := sdk.Events{ - sdk.NewEvent( - sdk.EventTypeTx, - sdk.NewAttribute(sdk.AttributeKeyFee, fee.String()), - sdk.NewAttribute(sdk.AttributeKeyFeePayer, deductFeesFrom.String()), - ), - } - ctx.EventManager().EmitEvents(events) - - return nil -} - -// DeductFees deducts fees from the given account. -func DeductFees(bankKeeper types.BankKeeper, ctx sdk.Context, acc types.AccountI, fees sdk.Coins) error { - if !fees.IsValid() { - return errorsmod.Wrapf(sdkerrors.ErrInsufficientFee, "invalid fee amount: %s", fees) - } - - err := bankKeeper.SendCoinsFromAccountToModule(ctx, acc.GetAddress(), types.FeeCollectorName, fees) - if err != nil { - return errorsmod.Wrapf(sdkerrors.ErrInsufficientFunds, err.Error()) - } - - return nil -} - -// checkTxFee implements the default fee logic, where the minimum price per -// unit of gas is fixed and set by each validator, can the tx priority is computed from the gas price. -// Transaction with only oracle messages will skip gas fee check and will have the most priority. -// It also checks enough fee for treasury tax -func (fd FeeDecorator) checkTxFee(ctx sdk.Context, tx sdk.Tx, taxes sdk.Coins) (int64, error) { - feeTx, ok := tx.(sdk.FeeTx) - if !ok { - return 0, errorsmod.Wrap(sdkerrors.ErrTxDecode, "Tx must be a FeeTx") - } - - feeCoins := feeTx.GetFee() - gas := feeTx.GetGas() - msgs := feeTx.GetMsgs() - isOracleTx := isOracleTx(msgs) - - // 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. - 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()) - } - } - - requiredFees := requiredGasFees.Add(taxes...) - - // Check required fees - if !requiredFees.IsZero() && !feeCoins.IsAnyGTE(requiredFees) { - return 0, errorsmod.Wrapf(sdkerrors.ErrInsufficientFee, "insufficient fees; got: %q, required: %q = %q(gas) + %q(stability)", feeCoins, requiredFees, requiredGasFees, taxes) - } - } - - priority := int64(math.MaxInt64) - - if !isOracleTx { - priority = getTxPriority(feeCoins, int64(gas)) - } - - return priority, nil -} - -// getTxPriority returns a naive tx priority based on the amount of the smallest denomination of the gas price -// provided in a transaction. -// NOTE: This implementation should be used with a great consideration as it opens potential attack vectors -// where txs with multiple coins could not be prioritize as expected. -func getTxPriority(fee sdk.Coins, gas int64) int64 { - var priority int64 - for _, c := range fee { - p := int64(math.MaxInt64) - gasPrice := c.Amount.QuoRaw(gas) - if gasPrice.IsInt64() { - p = gasPrice.Int64() - } - if priority == 0 || p < priority { - priority = p - } - } - - return priority -} diff --git a/custom/auth/ante/fee_burntax.go b/custom/auth/ante/fee_burntax.go deleted file mode 100644 index fd76cd3ea..000000000 --- a/custom/auth/ante/fee_burntax.go +++ /dev/null @@ -1,39 +0,0 @@ -package ante - -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/types" - - treasury "github.com/classic-terra/core/v3/x/treasury/types" -) - -// BurnTaxSplit splits -func (fd FeeDecorator) BurnTaxSplit(ctx sdk.Context, taxes sdk.Coins) (err error) { - burnSplitRate := fd.treasuryKeeper.GetBurnSplitRate(ctx) - - if burnSplitRate.IsPositive() { - distributionDeltaCoins := sdk.NewCoins() - - for _, taxCoin := range taxes { - splitcoinAmount := burnSplitRate.MulInt(taxCoin.Amount).RoundInt() - distributionDeltaCoins = distributionDeltaCoins.Add(sdk.NewCoin(taxCoin.Denom, splitcoinAmount)) - } - - taxes = taxes.Sub(distributionDeltaCoins...) - } - - if !taxes.IsZero() { - if err = fd.bankKeeper.SendCoinsFromModuleToModule( - ctx, - types.FeeCollectorName, - treasury.BurnModuleName, - taxes, - ); err != nil { - return errorsmod.Wrapf(sdkerrors.ErrInsufficientFunds, err.Error()) - } - } - - return nil -} diff --git a/custom/auth/ante/fee_test.go b/custom/auth/ante/fee_test.go deleted file mode 100644 index 50dcc8c4c..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" - "github.com/classic-terra/core/v3/custom/auth/ante" - 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" -) - -func (s *AnteTestSuite) TestDeductFeeDecorator_ZeroGas() { - s.SetupTest(true) // setup - s.txBuilder = s.clientCtx.TxConfig.NewTxBuilder() - - mfd := ante.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 := ante.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 := ante.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 := ante.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 := ante.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 := ante.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 := ante.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 := ante.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 := ante.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 := ante.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 := ante.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 := ante.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 := ante.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 := ante.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/ante/integration_test.go b/custom/auth/ante/integration_test.go deleted file mode 100644 index ffadd5983..000000000 --- a/custom/auth/ante/integration_test.go +++ /dev/null @@ -1,220 +0,0 @@ -package ante_test - -import ( - "fmt" - - cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" - "github.com/cosmos/cosmos-sdk/testutil/testdata" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/auth/ante" - "github.com/cosmos/cosmos-sdk/x/auth/types" - "github.com/cosmos/cosmos-sdk/x/bank/testutil" - banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" - - wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types" - - customante "github.com/classic-terra/core/v3/custom/auth/ante" - core "github.com/classic-terra/core/v3/types" - treasurytypes "github.com/classic-terra/core/v3/x/treasury/types" -) - -// go test -v -run ^TestAnteTestSuite/TestIntegrationTaxExemption$ github.com/classic-terra/core/v3/custom/auth/ante -func (s *AnteTestSuite) TestIntegrationTaxExemption() { - // keys and addresses - var privs []cryptotypes.PrivKey - var addrs []sdk.AccAddress - - // 0, 1: exemption - // 2, 3: normal - for i := 0; i < 4; i++ { - priv, _, addr := testdata.KeyTestPubAddr() - privs = append(privs, priv) - addrs = append(addrs, addr) - } - - // set send amount - sendAmt := int64(1_000_000) - sendCoin := sdk.NewInt64Coin(core.MicroSDRDenom, sendAmt) - feeAmt := int64(1000) - - cases := []struct { - name string - msgSigner cryptotypes.PrivKey - msgCreator func() []sdk.Msg - expectedFeeAmount 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 - }, - expectedFeeAmount: 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 - expectedFeeAmount: 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 - expectedFeeAmount: feeAmt, - }, { - name: "MsgSend(exemption -> exemption), MsgMultiSend(exemption -> normal, 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.Add(sendCoin)), - }, - }, - []banktypes.Output{ - { - Address: addrs[2].String(), - Coins: sdk.NewCoins(sendCoin), - }, - { - Address: addrs[1].String(), - Coins: sdk.NewCoins(sendCoin), - }, - }, - ) - msgs = append(msgs, msg2) - - return msgs - }, - expectedFeeAmount: feeAmt * 2, - }, - } - - for _, c := range cases { - s.SetupTest(true) // setup - tk := s.app.TreasuryKeeper - ak := s.app.AccountKeeper - bk := s.app.BankKeeper - dk := s.app.DistrKeeper - wk := s.app.WasmKeeper - - // Set burn split rate to 50% - // fee amount should be 500, 50% of 10000 - burnSplitRate := sdk.NewDecWithPrec(5, 1) - tk.SetBurnSplitRate(s.ctx, burnSplitRate) // 50% - - feeCollector := ak.GetModuleAccount(s.ctx, types.FeeCollectorName) - burnModule := ak.GetModuleAccount(s.ctx, treasurytypes.BurnModuleName) - - encodingConfig := s.SetupEncoding() - wasmConfig := wasmtypes.DefaultWasmConfig() - antehandler, err := customante.NewAnteHandler( - customante.HandlerOptions{ - AccountKeeper: ak, - BankKeeper: bk, - WasmKeeper: &wk, - FeegrantKeeper: s.app.FeeGrantKeeper, - OracleKeeper: s.app.OracleKeeper, - TreasuryKeeper: s.app.TreasuryKeeper, - SigGasConsumer: ante.DefaultSigVerificationGasConsumer, - SignModeHandler: encodingConfig.TxConfig.SignModeHandler(), - IBCKeeper: *s.app.IBCKeeper, - DistributionKeeper: dk, - WasmConfig: &wasmConfig, - TXCounterStoreKey: s.app.GetKey(wasmtypes.StoreKey), - }, - ) - s.Require().NoError(err) - - for i := 0; i < 4; i++ { - coins := sdk.NewCoins(sdk.NewInt64Coin(core.MicroSDRDenom, 1_000_000)) - testutil.FundAccount(s.app.BankKeeper, s.ctx, addrs[i], coins) - } - - s.txBuilder = s.clientCtx.TxConfig.NewTxBuilder() - - tk.AddBurnTaxExemptionAddress(s.ctx, addrs[0].String()) - tk.AddBurnTaxExemptionAddress(s.ctx, addrs[1].String()) - - s.Run(c.name, func() { - // case 1 provides zero fee so not enough fee - // case 2 provides enough fee - feeCases := []int64{0, feeAmt} - for i := 0; i < 1; i++ { - feeAmount := sdk.NewCoins(sdk.NewInt64Coin(core.MicroSDRDenom, feeCases[i])) - gasLimit := testdata.NewTestGasLimit() - s.Require().NoError(s.txBuilder.SetMsgs(c.msgCreator()...)) - s.txBuilder.SetFeeAmount(feeAmount) - s.txBuilder.SetGasLimit(gasLimit) - - privs, accNums, accSeqs := []cryptotypes.PrivKey{c.msgSigner}, []uint64{3}, []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()) - - feeCollectorBefore := bk.GetBalance(s.ctx, feeCollector.GetAddress(), core.MicroSDRDenom) - burnBefore := bk.GetBalance(s.ctx, burnModule.GetAddress(), core.MicroSDRDenom) - communityBefore := dk.GetFeePool(s.ctx).CommunityPool.AmountOf(core.MicroSDRDenom) - supplyBefore := bk.GetSupply(s.ctx, core.MicroSDRDenom) - - _, err = antehandler(s.ctx, tx, false) - if i == 0 && c.expectedFeeAmount != 0 { - s.Require().EqualError(err, fmt.Sprintf( - "insufficient fees; got: \"\", required: \"%dusdr\" = \"\"(gas) + \"%dusdr\"(stability): insufficient fee", - c.expectedFeeAmount, c.expectedFeeAmount)) - } else { - s.Require().NoError(err) - } - - feeCollectorAfter := bk.GetBalance(s.ctx, feeCollector.GetAddress(), core.MicroSDRDenom) - burnAfter := bk.GetBalance(s.ctx, burnModule.GetAddress(), core.MicroSDRDenom) - communityAfter := dk.GetFeePool(s.ctx).CommunityPool.AmountOf(core.MicroSDRDenom) - supplyAfter := bk.GetSupply(s.ctx, core.MicroSDRDenom) - - if i == 0 { - s.Require().Equal(feeCollectorBefore, feeCollectorAfter) - s.Require().Equal(burnBefore, burnAfter) - s.Require().Equal(communityBefore, communityAfter) - s.Require().Equal(supplyBefore, supplyAfter) - } - - if i == 1 { - s.Require().Equal(feeCollectorBefore, feeCollectorAfter) - splitAmount := burnSplitRate.MulInt64(c.expectedFeeAmount).TruncateInt() - s.Require().Equal(burnBefore, burnAfter.AddAmount(splitAmount)) - s.Require().Equal(communityBefore, communityAfter.Add(sdk.NewDecFromInt(splitAmount))) - s.Require().Equal(supplyBefore, supplyAfter.SubAmount(splitAmount)) - } - } - }) - } -} diff --git a/custom/auth/post/post.go b/custom/auth/post/post.go index 95f0f1867..5183346cc 100644 --- a/custom/auth/post/post.go +++ b/custom/auth/post/post.go @@ -3,12 +3,22 @@ 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" + 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 tax2gastypes.BankKeeper + FeegrantKeeper tax2gastypes.FeegrantKeeper + DyncommKeeper dyncommkeeper.Keeper + TreasuryKeeper tax2gastypes.TreasuryKeeper + DistrKeeper tax2gastypes.DistrKeeper + Tax2Gaskeeper tax2gaskeeper.Keeper } // NewPostHandler returns an PostHandler that checks and set target @@ -16,5 +26,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.FeegrantKeeper, options.TreasuryKeeper, options.DistrKeeper, options.Tax2Gaskeeper), ), nil } diff --git a/custom/auth/tx/service.go b/custom/auth/tx/service.go index 63710d04e..92349bd78 100644 --- a/custom/auth/tx/service.go +++ b/custom/auth/tx/service.go @@ -9,6 +9,7 @@ import ( "google.golang.org/grpc/status" customante "github.com/classic-terra/core/v3/custom/auth/ante" + tax2gasUtils "github.com/classic-terra/core/v3/x/tax2gas/utils" "github.com/cosmos/cosmos-sdk/client" codectypes "github.com/cosmos/cosmos-sdk/codec/types" @@ -52,7 +53,7 @@ func (ts txServer) ComputeTax(c context.Context, req *ComputeTaxRequest) (*Compu return nil, status.Errorf(codes.InvalidArgument, "empty txBytes is not allowed") } - taxAmount := customante.FilterMsgAndComputeTax(ctx, ts.treasuryKeeper, msgs...) + taxAmount := tax2gasUtils.FilterMsgAndComputeTax(ctx, ts.treasuryKeeper, msgs...) return &ComputeTaxResponse{ TaxAmount: taxAmount, }, nil diff --git a/custom/wasm/keeper/handler_plugin.go b/custom/wasm/keeper/handler_plugin.go index f3a24801b..836fff96d 100644 --- a/custom/wasm/keeper/handler_plugin.go +++ b/custom/wasm/keeper/handler_plugin.go @@ -1,20 +1,28 @@ package keeper import ( - "github.com/classic-terra/core/v3/custom/auth/ante" - treasurykeeper "github.com/classic-terra/core/v3/x/treasury/keeper" + "regexp" + "strings" - wasmvmtypes "github.com/CosmWasm/wasmvm/types" + errorsmod "cosmossdk.io/errors" "github.com/cosmos/cosmos-sdk/baseapp" codectypes "github.com/cosmos/cosmos-sdk/codec/types" sdk "github.com/cosmos/cosmos-sdk/types" 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" + wasmvmtypes "github.com/CosmWasm/wasmvm/types" + + marketexported "github.com/classic-terra/core/v3/x/market/exported" + tax2gaskeeper "github.com/classic-terra/core/v3/x/tax2gas/keeper" + tax2gastypes "github.com/classic-terra/core/v3/x/tax2gas/types" + tax2gasutils "github.com/classic-terra/core/v3/x/tax2gas/utils" + treasurykeeper "github.com/classic-terra/core/v3/x/treasury/keeper" ) // msgEncoder is an extension point to customize encodings @@ -35,6 +43,7 @@ type SDKMessageHandler struct { treasuryKeeper treasurykeeper.Keeper accountKeeper authkeeper.AccountKeeper bankKeeper bankKeeper.Keeper + tax2gaskeeper tax2gaskeeper.Keeper } func NewMessageHandler( @@ -45,6 +54,7 @@ func NewMessageHandler( bankKeeper bankKeeper.Keeper, treasuryKeeper treasurykeeper.Keeper, accountKeeper authkeeper.AccountKeeper, + tax2gaskeeper tax2gaskeeper.Keeper, unpacker codectypes.AnyUnpacker, portSource wasmtypes.ICS20TransferPortSource, customEncoders ...*wasmkeeper.MessageEncoders, @@ -54,19 +64,20 @@ func NewMessageHandler( encoders = encoders.Merge(e) } return wasmkeeper.NewMessageHandlerChain( - NewSDKMessageHandler(router, encoders, treasuryKeeper, accountKeeper, bankKeeper), + NewSDKMessageHandler(router, encoders, treasuryKeeper, accountKeeper, bankKeeper, tax2gaskeeper), wasmkeeper.NewIBCRawPacketHandler(ics4Wrapper, channelKeeper, capabilityKeeper), wasmkeeper.NewBurnCoinMessageHandler(bankKeeper), ) } -func NewSDKMessageHandler(router MessageRouter, encoders msgEncoder, treasuryKeeper treasurykeeper.Keeper, accountKeeper authkeeper.AccountKeeper, bankKeeper bankKeeper.Keeper) SDKMessageHandler { +func NewSDKMessageHandler(router MessageRouter, encoders msgEncoder, treasuryKeeper treasurykeeper.Keeper, accountKeeper authkeeper.AccountKeeper, bankKeeper bankKeeper.Keeper, tax2gaskeeper tax2gaskeeper.Keeper) SDKMessageHandler { return SDKMessageHandler{ router: router, encoders: encoders, treasuryKeeper: treasuryKeeper, accountKeeper: accountKeeper, bankKeeper: bankKeeper, + tax2gaskeeper: tax2gaskeeper, } } @@ -77,16 +88,19 @@ 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) - if !taxes.IsZero() { - eventManager := sdk.NewEventManager() - contractAcc := h.accountKeeper.GetAccount(ctx, contractAddr) - if err := cosmosante.DeductFees(h.bankKeeper, ctx.WithEventManager(eventManager), contractAcc, taxes); err != nil { - return nil, nil, err - } + if h.tax2gaskeeper.IsEnabled(ctx) { + taxes := FilterMsgAndComputeTax(ctx, h.treasuryKeeper, sdkMsg) + if !taxes.IsZero() { + eventManager := sdk.NewEventManager() - events = eventManager.Events() + taxGas, err := tax2gasutils.ComputeGas(h.tax2gaskeeper.GetGasPrices(ctx), taxes) + if err != nil { + return nil, nil, err + } + ctx.TaxGasMeter().ConsumeGas(taxGas, "tax gas") + + events = eventManager.Events() + } } res, err := h.handleSdkMessage(ctx, contractAddr, sdkMsg) @@ -112,7 +126,7 @@ func (h SDKMessageHandler) handleSdkMessage(ctx sdk.Context, contractAddr sdk.Ad // make sure this account can send it for _, acct := range msg.GetSigners() { if !acct.Equals(contractAddr) { - return nil, sdkerrors.Wrap(sdkerrors.ErrUnauthorized, "contract doesn't have permission") + return nil, errorsmod.Wrap(sdkerrors.ErrUnauthorized, "contract doesn't have permission") } } @@ -127,5 +141,104 @@ func (h SDKMessageHandler) handleSdkMessage(ctx sdk.Context, contractAddr sdk.Ad // proto messages and has registered all `Msg services`, then this // path should never be called, because all those Msgs should be // registered within the `msgServiceRouter` already. - return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "can't route message %+v", msg) + return nil, errorsmod.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 tax2gastypes.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 tax2gastypes.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 } diff --git a/go.mod b/go.mod index 992398a07..64b51c509 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ require ( cosmossdk.io/math v1.3.0 cosmossdk.io/simapp v0.0.0-20230602123434-616841b9704d github.com/CosmWasm/wasmd v0.45.0 - github.com/CosmWasm/wasmvm v1.5.0 + github.com/CosmWasm/wasmvm v1.5.2 github.com/cometbft/cometbft v0.37.4 github.com/cometbft/cometbft-db v0.8.0 github.com/cosmos/cosmos-sdk v0.47.10 @@ -225,11 +225,11 @@ replace ( ) replace ( - github.com/CosmWasm/wasmd => github.com/classic-terra/wasmd v0.45.0-terra.3 + github.com/CosmWasm/wasmd => github.com/classic-terra/wasmd v0.45.0-terra.5 // use cometbft github.com/cometbft/cometbft => github.com/classic-terra/cometbft v0.37.4-terra1 github.com/cometbft/cometbft-db => github.com/cometbft/cometbft-db v0.8.0 - github.com/cosmos/cosmos-sdk => github.com/classic-terra/cosmos-sdk v0.47.10-terra.1 + github.com/cosmos/cosmos-sdk => github.com/classic-terra/cosmos-sdk v0.47.10-terra.1.0.20240723054936-404ac399d771 github.com/cosmos/ibc-go/v7 => github.com/classic-terra/ibc-go/v7 v7.4.0-terra github.com/cosmos/ledger-cosmos-go => github.com/terra-money/ledger-terra-go v0.11.2 // replace goleveldb to optimized one diff --git a/go.sum b/go.sum index d5e71c43c..e0b9cbf58 100644 --- a/go.sum +++ b/go.sum @@ -222,8 +222,8 @@ github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg6 github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/ChainSafe/go-schnorrkel v1.0.0 h1:3aDA67lAykLaG1y3AOjs88dMxC88PgUuHRrLeDnvGIM= github.com/ChainSafe/go-schnorrkel v1.0.0/go.mod h1:dpzHYVxLZcp8pjlV+O+UR8K0Hp/z7vcchBSbMBEhCw4= -github.com/CosmWasm/wasmvm v1.5.0 h1:3hKeT9SfwfLhxTGKH3vXaKFzBz1yuvP8SlfwfQXbQfw= -github.com/CosmWasm/wasmvm v1.5.0/go.mod h1:fXB+m2gyh4v9839zlIXdMZGeLAxqUdYdFQqYsTha2hc= +github.com/CosmWasm/wasmvm v1.5.2 h1:+pKB1Mz9GZVt1vadxB+EDdD1FOz3dMNjIKq/58/lrag= +github.com/CosmWasm/wasmvm v1.5.2/go.mod h1:Q0bSEtlktzh7W2hhEaifrFp1Erx11ckQZmjq8FLCyys= github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/DataDog/zstd v1.5.0/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw= @@ -350,14 +350,14 @@ github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6D github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= github.com/classic-terra/cometbft v0.37.4-terra1 h1:eT5B2n5KKi5WVW+3ZNOVTmtfKKaZrXOLX9G80m9mhZo= github.com/classic-terra/cometbft v0.37.4-terra1/go.mod h1:vFqj7Qe3uFFJvHZleTJPQDmJ/WscXHi4rKWqiCAaNZk= -github.com/classic-terra/cosmos-sdk v0.47.10-terra.1 h1:ek0vQ435fpeP3xGhszDO2yMIRy5XGMj9MCTlvpMUIkw= -github.com/classic-terra/cosmos-sdk v0.47.10-terra.1/go.mod h1:4mBvTB8zevoeTuQufWwTcNnthGG2afXO+9D42BKzlRo= +github.com/classic-terra/cosmos-sdk v0.47.10-terra.1.0.20240723054936-404ac399d771 h1:9yPDQUGx2iclFqwlahbzbNuNCAngivpTvOnXvjo5p0k= +github.com/classic-terra/cosmos-sdk v0.47.10-terra.1.0.20240723054936-404ac399d771/go.mod h1:4mBvTB8zevoeTuQufWwTcNnthGG2afXO+9D42BKzlRo= github.com/classic-terra/goleveldb v0.0.0-20230914223247-2b28f6655121 h1:fjpWDB0hm225wYg9vunyDyTH8ftd5xEUgINJKidj+Tw= github.com/classic-terra/goleveldb v0.0.0-20230914223247-2b28f6655121/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= github.com/classic-terra/ibc-go/v7 v7.4.0-terra h1:hawaq62XKlxyc8xLyIcc6IujDDEbqDBU+2U15SF+hj8= github.com/classic-terra/ibc-go/v7 v7.4.0-terra/go.mod h1:s0lxNkjVIqsb8AVltL0qhzxeLgOKvWZrknPuvgjlEQ8= -github.com/classic-terra/wasmd v0.45.0-terra.3 h1:Fpjrjco0ig4dLwX6KrT+z0Zjo2iJCggM2X0JppyA/ko= -github.com/classic-terra/wasmd v0.45.0-terra.3/go.mod h1:pTPOut260rZ3J0WROheOgNWDV/vk/AeRdXmM1JOtMjk= +github.com/classic-terra/wasmd v0.45.0-terra.5 h1:0fuc4lS1Z0Egci6hwK4DZqOwF2l9fGsZuPTZ1akObFY= +github.com/classic-terra/wasmd v0.45.0-terra.5/go.mod h1:r/AxjzSLyrQbrANEsV/d+qf/vmCDFiAoVwWenGs23ZY= github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cloudflare/cloudflare-go v0.14.0/go.mod h1:EnwdgGMaFOruiPZRFSgn+TsQ3hQ7C/YWzIGLeu5c304= diff --git a/proto/terra/tax2gas/v1beta1/genesis.proto b/proto/terra/tax2gas/v1beta1/genesis.proto new file mode 100644 index 000000000..611f8108f --- /dev/null +++ b/proto/terra/tax2gas/v1beta1/genesis.proto @@ -0,0 +1,40 @@ +syntax = "proto3"; +package terra.tax2gas.v1beta1; + +import "gogoproto/gogo.proto"; +import "cosmos/base/v1beta1/coin.proto"; +import "amino/amino.proto"; + +option go_package = "github.com/classic-terra/core/v3/x/tax2gas/types"; + +message Params { + option (gogoproto.goproto_stringer) = true; + option (amino.name) = "terra/x/tax2gas/Params"; + + repeated cosmos.base.v1beta1.DecCoin gas_prices = 1 [ + (gogoproto.moretags) = "yaml:\"gas_prices\"", + (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.DecCoins", + (gogoproto.nullable) = false, + (amino.dont_omitempty) = true + ]; + + bool enabled = 2; + + // bypass_min_fee_msg_types defines a list of message type urls + // that are free of fee charge. + repeated string bypass_min_fee_msg_types = 3 [ + (gogoproto.jsontag) = "bypass_min_fee_msg_types,omitempty", + (gogoproto.moretags) = "yaml:\"bypass_min_fee_msg_types\"" + ]; + + // max_total_bypass_min_fee_msg_gas_usage defines the total maximum gas usage + // allowed for a transaction containing only messages of types in bypass_min_fee_msg_types + // to bypass fee charge. + uint64 max_total_bypass_min_fee_msg_gas_usage = 4; +} + +// GenesisState defines the tax2gas module's genesis state. +message GenesisState { + // params is the container of tax2gas parameters. + Params params = 1 [(gogoproto.nullable) = false]; +} \ No newline at end of file diff --git a/proto/terra/tax2gas/v1beta1/query.proto b/proto/terra/tax2gas/v1beta1/query.proto new file mode 100644 index 000000000..78bab4adb --- /dev/null +++ b/proto/terra/tax2gas/v1beta1/query.proto @@ -0,0 +1,20 @@ +syntax = "proto3"; +package terra.tax2gas.v1beta1; + +import "gogoproto/gogo.proto"; +import "google/api/annotations.proto"; +import "terra/tax2gas/v1beta1/genesis.proto"; + +option go_package = "github.com/classic-terra/core/v3/x/tax2gas/types"; + +service Query { + rpc Params(QueryParamsRequest) returns (QueryParamsResponse) { + option (google.api.http).get = "/terra/tax2gas/Params"; + } +} + +//=============================== Params +message QueryParamsRequest {} +message QueryParamsResponse { + Params params = 1 [(gogoproto.nullable) = false]; +} \ No newline at end of file diff --git a/proto/terra/tax2gas/v1beta1/tx.proto b/proto/terra/tax2gas/v1beta1/tx.proto new file mode 100644 index 000000000..87d8f61c1 --- /dev/null +++ b/proto/terra/tax2gas/v1beta1/tx.proto @@ -0,0 +1,38 @@ +syntax = "proto3"; +package terra.tax2gas.v1beta1; + +import "gogoproto/gogo.proto"; +import "cosmos/msg/v1/msg.proto"; +import "amino/amino.proto"; +import "cosmos_proto/cosmos.proto"; +import "terra/tax2gas/v1beta1/genesis.proto"; + +option go_package = "github.com/classic-terra/core/v3/x/tax2gas/types"; + +service Msg { + option (cosmos.msg.v1.service) = true; + + rpc UpdateParams(MsgUpdateParams) returns (MsgUpdateParamsResponse); +} + +// MsgUpdateParams is the Msg/UpdateParams request type. +// +// Since: cosmos-sdk 0.47 +message MsgUpdateParams { + option (cosmos.msg.v1.signer) = "authority"; + + // authority is the address that controls the module (defaults to x/gov unless overwritten). + string authority = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"]; + option (amino.name) = "terra/x/tax2gas/MsgUpdateParams"; + + // params defines the x/tax2gas parameters to update. + // + // NOTE: All parameters must be supplied. + Params params = 2 [(gogoproto.nullable) = false, (amino.dont_omitempty) = true]; +} + +// MsgUpdateParamsResponse defines the response structure for executing a +// MsgUpdateParams message. +// +// Since: cosmos-sdk 0.47 +message MsgUpdateParamsResponse {} \ No newline at end of file diff --git a/proto/terra/treasury/v1beta1/treasury.proto b/proto/terra/treasury/v1beta1/treasury.proto index 1d91a9c63..a6e0b8893 100644 --- a/proto/terra/treasury/v1beta1/treasury.proto +++ b/proto/terra/treasury/v1beta1/treasury.proto @@ -41,6 +41,12 @@ message Params { (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", (gogoproto.nullable) = false ]; + string oracle_split = 10 [ + (cosmos_proto.scalar) = "cosmos.Dec", + (gogoproto.moretags) = "yaml:\"oracle_split\"", + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", + (gogoproto.nullable) = false + ]; } // PolicyConstraints - defines policy constraints can be applied in tax & reward policies diff --git a/scripts/protocgen.sh b/scripts/protocgen.sh index bfcae1a32..674c4958a 100755 --- a/scripts/protocgen.sh +++ b/scripts/protocgen.sh @@ -2,9 +2,6 @@ set -eo pipefail -# get protoc executions -go get github.com/regen-network/cosmos-proto/protoc-gen-gocosmos 2>/dev/null - echo "Generating gogo proto code" cd proto proto_dirs=$(find terra -path -prune -o -name '*.proto' -print0 | xargs -0 -n1 dirname | sort | uniq) diff --git a/tests/e2e/configurer/chain/commands.go b/tests/e2e/configurer/chain/commands.go index 954868ece..756af93d2 100644 --- a/tests/e2e/configurer/chain/commands.go +++ b/tests/e2e/configurer/chain/commands.go @@ -25,18 +25,19 @@ import ( func (n *NodeConfig) StoreWasmCode(wasmFile, from string) { n.LogActionF("storing wasm code from file %s", wasmFile) - cmd := []string{"terrad", "tx", "wasm", "store", wasmFile, fmt.Sprintf("--from=%s", from)} + cmd := []string{"terrad", "tx", "wasm", "store", wasmFile, fmt.Sprintf("--from=%s", from), "--fees=10uluna", "--gas=2000000"} _, _, err := n.containerManager.ExecTxCmd(n.t, n.chainID, n.Name, cmd) require.NoError(n.t, err) n.LogActionF("successfully stored") } -func (n *NodeConfig) InstantiateWasmContract(codeID, initMsg, amount, from string) { +func (n *NodeConfig) InstantiateWasmContract(codeID, initMsg, amount, from string, gasLimit string, fees sdk.Coins) { n.LogActionF("instantiating wasm contract %s with %s", codeID, initMsg) cmd := []string{"terrad", "tx", "wasm", "instantiate", codeID, initMsg, fmt.Sprintf("--from=%s", from), "--no-admin", "--label=ratelimit"} if amount != "" { cmd = append(cmd, fmt.Sprintf("--amount=%s", amount)) } + cmd = append(cmd, "--gas", gasLimit, "--fees", fees.String()) n.LogActionF(strings.Join(cmd, " ")) _, _, err := n.containerManager.ExecTxCmd(n.t, n.chainID, n.Name, cmd) @@ -45,7 +46,7 @@ func (n *NodeConfig) InstantiateWasmContract(codeID, initMsg, amount, from strin n.LogActionF("successfully initialized") } -func (n *NodeConfig) Instantiate2WasmContract(codeID, initMsg, salt, amount, fee, from string) { +func (n *NodeConfig) Instantiate2WasmContract(codeID, initMsg, salt, amount, from string, gasLimit string, fees sdk.Coins) { n.LogActionF("instantiating wasm contract %s with %s", codeID, initMsg) encodedSalt := make([]byte, hex.EncodedLen(len([]byte(salt)))) hex.Encode(encodedSalt, []byte(salt)) @@ -53,24 +54,20 @@ func (n *NodeConfig) Instantiate2WasmContract(codeID, initMsg, salt, amount, fee if amount != "" { cmd = append(cmd, fmt.Sprintf("--amount=%s", amount)) } - if fee != "" { - cmd = append(cmd, fmt.Sprintf("--fees=%s", fee)) - } + cmd = append(cmd, "--gas", gasLimit, "--fees", fees.String()) n.LogActionF(strings.Join(cmd, " ")) _, _, err := n.containerManager.ExecTxCmd(n.t, n.chainID, n.Name, cmd) require.NoError(n.t, err) n.LogActionF("successfully initialized") } -func (n *NodeConfig) WasmExecute(contract, execMsg, amount, fee, from string) { +func (n *NodeConfig) WasmExecute(contract, execMsg, amount, from string, gasLimit string, fees sdk.Coins) { n.LogActionF("executing %s on wasm contract %s from %s", execMsg, contract, from) cmd := []string{"terrad", "tx", "wasm", "execute", contract, execMsg, fmt.Sprintf("--from=%s", from)} if amount != "" { cmd = append(cmd, fmt.Sprintf("--amount=%s", amount)) } - if fee != "" { - cmd = append(cmd, fmt.Sprintf("--fees=%s", fee)) - } + cmd = append(cmd, "--gas", gasLimit, "--fees", fees.String()) n.LogActionF(strings.Join(cmd, " ")) _, _, err := n.containerManager.ExecTxCmd(n.t, n.chainID, n.Name, cmd) require.NoError(n.t, err) @@ -121,6 +118,7 @@ func (n *NodeConfig) SubmitAddBurnTaxExemptionAddressProposal(addresses []string "add-burn-tax-exemption-address", strings.Join(addresses, ","), "--title=\"burn tax exemption address\"", "--description=\"\"burn tax exemption address", + "--gas", "300000", "--gas-prices", "1uluna", fmt.Sprintf("--from=%s", walletName), } @@ -149,7 +147,7 @@ func (n *NodeConfig) FailIBCTransfer(from, recipient, amount string) { func (n *NodeConfig) SendIBCTransfer(from, recipient, amount, memo string) { n.LogActionF("IBC sending %s from %s to %s. memo: %s", amount, from, recipient, memo) - cmd := []string{"terrad", "tx", "ibc-transfer", "transfer", "transfer", "channel-0", recipient, amount, fmt.Sprintf("--from=%s", from), "--memo", memo} + cmd := []string{"terrad", "tx", "ibc-transfer", "transfer", "transfer", "channel-0", recipient, amount, fmt.Sprintf("--from=%s", from), "--memo", memo, "--fees=10uluna"} _, _, err := n.containerManager.ExecTxCmdWithSuccessString(n.t, n.chainID, n.Name, cmd, "\"code\":0") require.NoError(n.t, err) @@ -168,7 +166,7 @@ func (n *NodeConfig) SubmitTextProposal(text string, initialDeposit sdk.Coin) { func (n *NodeConfig) DepositProposal(proposalNumber int) { n.LogActionF("depositing on proposal: %d", proposalNumber) deposit := sdk.NewCoin(initialization.TerraDenom, sdk.NewInt(20*assets.MicroUnit)).String() - cmd := []string{"terrad", "tx", "gov", "deposit", fmt.Sprintf("%d", proposalNumber), deposit, "--from=val"} + cmd := []string{"terrad", "tx", "gov", "deposit", fmt.Sprintf("%d", proposalNumber), deposit, "--from=val", "--gas", "300000", "--fees", "10000000uluna"} _, _, err := n.containerManager.ExecTxCmd(n.t, n.chainID, n.Name, cmd) require.NoError(n.t, err) n.LogActionF("successfully deposited on proposal %d", proposalNumber) @@ -176,7 +174,7 @@ func (n *NodeConfig) DepositProposal(proposalNumber int) { func (n *NodeConfig) VoteYesProposal(from string, proposalNumber int) { n.LogActionF("voting yes on proposal: %d", proposalNumber) - cmd := []string{"terrad", "tx", "gov", "vote", fmt.Sprintf("%d", proposalNumber), "yes", fmt.Sprintf("--from=%s", from)} + cmd := []string{"terrad", "tx", "gov", "vote", fmt.Sprintf("%d", proposalNumber), "yes", fmt.Sprintf("--from=%s", from), "--gas", "300000", "--fees", "10000000uluna"} _, _, err := n.containerManager.ExecTxCmd(n.t, n.chainID, n.Name, cmd) require.NoError(n.t, err) n.LogActionF("successfully voted yes on proposal %d", proposalNumber) @@ -213,36 +211,37 @@ func extractProposalIDFromResponse(response string) (int, error) { return proposalID, nil } -func (n *NodeConfig) BankSend(amount string, sendAddress string, receiveAddress string) { - n.BankSendWithWallet(amount, sendAddress, receiveAddress, "val") +func (n *NodeConfig) BankSend(amount string, sendAddress string, receiveAddress string, gasLimit string, fees sdk.Coins) { + n.BankSendWithWallet(amount, sendAddress, receiveAddress, "val", gasLimit, fees) } -func (n *NodeConfig) BankSendWithWallet(amount string, sendAddress string, receiveAddress string, walletName string) { +func (n *NodeConfig) BankSendWithWallet(amount string, sendAddress string, receiveAddress string, walletName string, gasLimit string, fees sdk.Coins) { n.LogActionF("bank sending %s from address %s to %s", amount, sendAddress, receiveAddress) cmd := []string{"terrad", "tx", "bank", "send", sendAddress, receiveAddress, amount, fmt.Sprintf("--from=%s", walletName)} + cmd = append(cmd, "--fees", fees.String(), "--gas", gasLimit) _, _, err := n.containerManager.ExecTxCmd(n.t, n.chainID, n.Name, cmd) require.NoError(n.t, err) n.LogActionF("successfully sent bank sent %s from address %s to %s", amount, sendAddress, receiveAddress) } -func (n *NodeConfig) BankSendFeeGrantWithWallet(amount string, sendAddress string, receiveAddress string, feeGranter string, walletName string) { +func (n *NodeConfig) BankSendFeeGrantWithWallet(amount string, sendAddress string, receiveAddress string, feeGranter string, walletName string, gasLimit string, fees sdk.Coins) { n.LogActionF("bank sending %s from address %s to %s", amount, sendAddress, receiveAddress) cmd := []string{"terrad", "tx", "bank", "send", sendAddress, receiveAddress, amount, fmt.Sprintf("--fee-granter=%s", feeGranter), fmt.Sprintf("--from=%s", walletName)} + cmd = append(cmd, "--fees", fees.String(), "--gas", gasLimit) _, _, err := n.containerManager.ExecTxCmd(n.t, n.chainID, n.Name, cmd) require.NoError(n.t, err) n.LogActionF("successfully sent bank sent %s from address %s to %s", amount, sendAddress, receiveAddress) } -func (n *NodeConfig) BankMultiSend(amount string, split bool, sendAddress string, receiveAddresses ...string) { +func (n *NodeConfig) BankMultiSend(amount string, split bool, sendAddress string, gasLimit string, fees sdk.Coins, receiveAddresses ...string) { n.LogActionF("bank multisending from %s to %s", sendAddress, strings.Join(receiveAddresses, ",")) cmd := []string{"terrad", "tx", "bank", "multi-send", sendAddress} cmd = append(cmd, receiveAddresses...) - cmd = append(cmd, amount, "--from=val") + cmd = append(cmd, amount, "--from=val", "--fees", fees.String(), "--gas", gasLimit) if split { cmd = append(cmd, "--split") } - _, _, err := n.containerManager.ExecTxCmd(n.t, n.chainID, n.Name, cmd) require.NoError(n.t, err) n.LogActionF("successfully multisent %s to %s", sendAddress, strings.Join(receiveAddresses, ",")) @@ -250,7 +249,7 @@ func (n *NodeConfig) BankMultiSend(amount string, split bool, sendAddress string func (n *NodeConfig) GrantAddress(granter, gratee string, spendLimit string, walletName string) { n.LogActionF("granting for address %s", gratee) - cmd := []string{"terrad", "tx", "feegrant", "grant", granter, gratee, fmt.Sprintf("--from=%s", walletName), fmt.Sprintf("--spend-limit=%s", spendLimit)} + cmd := []string{"terrad", "tx", "feegrant", "grant", granter, gratee, fmt.Sprintf("--from=%s", walletName), fmt.Sprintf("--spend-limit=%s", spendLimit), "--fees=10uluna"} _, _, err := n.containerManager.ExecTxCmd(n.t, n.chainID, n.Name, cmd) require.NoError(n.t, err) n.LogActionF("successfully granted for address %s", gratee) diff --git a/tests/e2e/e2e_test.go b/tests/e2e/e2e_test.go index d14e84dff..5780d74cd 100644 --- a/tests/e2e/e2e_test.go +++ b/tests/e2e/e2e_test.go @@ -28,7 +28,7 @@ func (s *IntegrationTestSuite) TestIBCWasmHooks() { nodeA.InstantiateWasmContract( strconv.Itoa(chainA.LatestCodeID), `{"count": "0"}`, "", - initialization.ValidatorWalletName) + initialization.ValidatorWalletName, "200000", sdk.NewCoins(sdk.NewCoin(initialization.TerraDenom, sdk.NewInt(10)))) contracts, err := nodeA.QueryContractsFromID(chainA.LatestCodeID) s.NoError(err) @@ -104,6 +104,7 @@ func (s *IntegrationTestSuite) TestAddBurnTaxExemptionAddress() { s.Require().Contains(whitelistedAddresses, whitelistAddr2) } +// Each tx gas will cost 2 uluna (1 is for ante handler, 1 is for post handler) func (s *IntegrationTestSuite) TestFeeTax() { chain := s.configurer.GetChainConfig(0) node, err := chain.GetDefaultNode() @@ -119,14 +120,16 @@ func (s *IntegrationTestSuite) TestFeeTax() { s.Require().NoError(err) test1Addr := node.CreateWallet("test1") + test2Addr := node.CreateWallet("test2") // Test 1: banktypes.MsgSend // burn tax with bank send - node.BankSend(transferCoin1.String(), validatorAddr, test1Addr) - subAmount := transferAmount1.Add(initialization.TaxRate.MulInt(transferAmount1).TruncateInt()) - decremented := validatorBalance.Sub(sdk.NewCoin(initialization.TerraDenom, subAmount)) + gasLimit := transferCoin1.Amount.MulRaw(initialization.E10).String() + node.BankSend(transferCoin1.String(), validatorAddr, test1Addr, gasLimit, sdk.NewCoins(transferCoin1)) + + decremented := validatorBalance.Sub(sdk.NewCoin(initialization.TerraDenom, subAmount.AddRaw(2))) newValidatorBalance, err := node.QuerySpecificBalance(validatorAddr, initialization.TerraDenom) s.Require().NoError(err) @@ -136,46 +139,22 @@ func (s *IntegrationTestSuite) TestFeeTax() { s.Require().Equal(balanceTest1.Amount, transferAmount1) s.Require().Equal(newValidatorBalance, decremented) - // Test 2: try bank send with grant - test2Addr := node.CreateWallet("test2") - transferAmount2 := sdkmath.NewInt(10000000) - transferCoin2 := sdk.NewCoin(initialization.TerraDenom, transferAmount2) - - node.BankSend(transferCoin2.String(), validatorAddr, test2Addr) - node.GrantAddress(test2Addr, test1Addr, transferCoin2.String(), "test2") - + // Test 2: banktypes.MsgMultiSend validatorBalance, err = node.QuerySpecificBalance(validatorAddr, initialization.TerraDenom) s.Require().NoError(err) - node.BankSendFeeGrantWithWallet(transferCoin2.String(), test1Addr, validatorAddr, test2Addr, "test1") - - newValidatorBalance, err = node.QuerySpecificBalance(validatorAddr, initialization.TerraDenom) - s.Require().NoError(err) - - balanceTest1, err = node.QuerySpecificBalance(test1Addr, initialization.TerraDenom) - s.Require().NoError(err) - - balanceTest2, err := node.QuerySpecificBalance(test2Addr, initialization.TerraDenom) - s.Require().NoError(err) - - s.Require().Equal(balanceTest1.Amount, transferAmount1.Sub(transferAmount2)) - s.Require().Equal(newValidatorBalance, validatorBalance.Add(transferCoin2)) - s.Require().Equal(balanceTest2.Amount, transferAmount2.Sub(initialization.TaxRate.MulInt(transferAmount2).TruncateInt())) - - // Test 3: banktypes.MsgMultiSend - validatorBalance, err = node.QuerySpecificBalance(validatorAddr, initialization.TerraDenom) - s.Require().NoError(err) - - node.BankMultiSend(transferCoin1.String(), false, validatorAddr, test1Addr, test2Addr) + totalTransferAmount := transferAmount1.Mul(sdk.NewInt(2)) + gasLimit = transferCoin1.Amount.MulRaw(initialization.E10).String() + node.BankMultiSend(transferCoin1.String(), false, validatorAddr, gasLimit, sdk.NewCoins(transferCoin1), test1Addr, test2Addr) newValidatorBalance, err = node.QuerySpecificBalance(validatorAddr, initialization.TerraDenom) s.Require().NoError(err) - totalTransferAmount := transferAmount1.Mul(sdk.NewInt(2)) subAmount = totalTransferAmount.Add(initialization.TaxRate.MulInt(totalTransferAmount).TruncateInt()) - s.Require().Equal(newValidatorBalance, validatorBalance.Sub(sdk.NewCoin(initialization.TerraDenom, subAmount))) + s.Require().Equal(newValidatorBalance, validatorBalance.Sub(sdk.NewCoin(initialization.TerraDenom, subAmount.AddRaw(2)))) } +// Each tx gas will cost 2 uluna (1 is for ante handler, 1 is for post handler) func (s *IntegrationTestSuite) TestFeeTaxWasm() { chain := s.configurer.GetChainConfig(0) node, err := chain.GetDefaultNode() @@ -184,14 +163,16 @@ func (s *IntegrationTestSuite) TestFeeTaxWasm() { testAddr := node.CreateWallet("test") transferAmount := sdkmath.NewInt(100000000) transferCoin := sdk.NewCoin(initialization.TerraDenom, transferAmount) - node.BankSend(fmt.Sprintf("%suluna", transferAmount.Mul(sdk.NewInt(4))), initialization.ValidatorWalletName, testAddr) + + gasLimit := transferCoin.Amount.MulRaw(initialization.E10).String() + node.BankSend(fmt.Sprintf("%suluna", transferAmount.Mul(sdk.NewInt(4))), initialization.ValidatorWalletName, testAddr, gasLimit, sdk.NewCoins(transferCoin)) node.StoreWasmCode("counter.wasm", initialization.ValidatorWalletName) chain.LatestCodeID = int(node.QueryLatestWasmCodeID()) // instantiate contract and transfer 100000000uluna node.InstantiateWasmContract( strconv.Itoa(chain.LatestCodeID), `{"count": "0"}`, transferCoin.String(), - "test") + "test", gasLimit, sdk.NewCoins(transferCoin)) contracts, err := node.QueryContractsFromID(chain.LatestCodeID) s.Require().NoError(err) @@ -199,17 +180,15 @@ func (s *IntegrationTestSuite) TestFeeTaxWasm() { balance1, err := node.QuerySpecificBalance(testAddr, initialization.TerraDenom) s.Require().NoError(err) - // 400000000 - 100000000 - 100000000 * TaxRate = 300000000 - 10000000 * TaxRate + // 400000000 - 100000000 - 100000000 * TaxRate - 2 (gas) = 300000000 - 10000000 * TaxRate - 2 (gas) taxAmount := initialization.TaxRate.MulInt(transferAmount).TruncateInt() - s.Require().Equal(balance1.Amount, transferAmount.Mul(sdk.NewInt(3)).Sub(taxAmount)) - - stabilityFee := sdk.NewDecWithPrec(2, 2).MulInt(transferAmount) + s.Require().Equal(balance1.Amount, transferAmount.Mul(sdk.NewInt(3)).Sub(taxAmount).SubRaw(2)) node.Instantiate2WasmContract( strconv.Itoa(chain.LatestCodeID), `{"count": "0"}`, "salt", transferCoin.String(), - fmt.Sprintf("%duluna", stabilityFee), "test") + "test", gasLimit, sdk.NewCoins(transferCoin)) contracts, err = node.QueryContractsFromID(chain.LatestCodeID) s.Require().NoError(err) @@ -217,16 +196,59 @@ func (s *IntegrationTestSuite) TestFeeTaxWasm() { balance2, err := node.QuerySpecificBalance(testAddr, initialization.TerraDenom) s.Require().NoError(err) - // balance1 - 100000000 - 100000000 * TaxRate + // balance1 - 100000000 - 100000000 * TaxRate - 2 (gas) taxAmount = initialization.TaxRate.MulInt(transferAmount).TruncateInt() - s.Require().Equal(balance2.Amount, balance1.Amount.Sub(transferAmount).Sub(taxAmount)) + s.Require().Equal(balance2.Amount, balance1.Amount.Sub(transferAmount).Sub(taxAmount).SubRaw(2)) contractAddr := contracts[0] - node.WasmExecute(contractAddr, `{"donate": {}}`, transferCoin.String(), fmt.Sprintf("%duluna", stabilityFee), "test") + node.WasmExecute(contractAddr, `{"donate": {}}`, transferCoin.String(), "test", gasLimit, sdk.NewCoins(transferCoin)) balance3, err := node.QuerySpecificBalance(testAddr, initialization.TerraDenom) s.Require().NoError(err) - // balance2 - 100000000 - 100000000 * TaxRate + // balance2 - 100000000 - 100000000 * TaxRate - 2 (gas) taxAmount = initialization.TaxRate.MulInt(transferAmount).TruncateInt() - s.Require().Equal(balance3.Amount, balance2.Amount.Sub(transferAmount).Sub(taxAmount)) + s.Require().Equal(balance3.Amount, balance2.Amount.Sub(transferAmount).Sub(taxAmount).SubRaw(2)) +} + +func (s *IntegrationTestSuite) TestFeeTaxGrant() { + chain := s.configurer.GetChainConfig(0) + node, err := chain.GetDefaultNode() + s.Require().NoError(err) + + transferAmount := sdkmath.NewInt(100000000) + transferCoin := sdk.NewCoin(initialization.TerraDenom, transferAmount) + + validatorAddr := node.GetWallet(initialization.ValidatorWalletName) + s.Require().NotEqual(validatorAddr, "") + + test1Addr := node.CreateWallet("test1") + test2Addr := node.CreateWallet("test2") + + // Test 1: try bank send with grant + gasLimit := transferCoin.Amount.MulRaw(initialization.E10).String() + node.BankSend(transferCoin.String(), validatorAddr, test1Addr, gasLimit, sdk.NewCoins(transferCoin)) + node.BankSend(transferCoin.String(), validatorAddr, test1Addr, gasLimit, sdk.NewCoins(transferCoin)) + node.BankSend(transferCoin.String(), validatorAddr, test2Addr, gasLimit, sdk.NewCoins(transferCoin)) + node.GrantAddress(test2Addr, test1Addr, transferCoin.String(), "test2") + + validatorBalance, err := node.QuerySpecificBalance(validatorAddr, initialization.TerraDenom) + s.Require().NoError(err) + + node.BankSendFeeGrantWithWallet(transferCoin.String(), test1Addr, validatorAddr, test2Addr, "test1", gasLimit, sdk.NewCoins(transferCoin)) + + newValidatorBalance, err := node.QuerySpecificBalance(validatorAddr, initialization.TerraDenom) + s.Require().NoError(err) + + balanceTest1, err := node.QuerySpecificBalance(test1Addr, initialization.TerraDenom) + s.Require().NoError(err) + + balanceTest2, err := node.QuerySpecificBalance(test2Addr, initialization.TerraDenom) + s.Require().NoError(err) + + s.Require().Equal(balanceTest1, transferCoin) + s.Require().Equal(newValidatorBalance, validatorBalance.Add(transferCoin)) + // addr2 lost 2uluna to pay for grant msg's gas, 100000000 * TaxRate + 2uluna to pay for bank send msg's tx fees, + s.Require().Equal(balanceTest2.Amount, transferAmount.Sub(initialization.TaxRate.MulInt(transferAmount).TruncateInt()).SubRaw(4)) + + // Test 2: try bank send with grant but pay by multiple fees denom } diff --git a/tests/e2e/initialization/config.go b/tests/e2e/initialization/config.go index 79a5bac58..ef96fb78c 100644 --- a/tests/e2e/initialization/config.go +++ b/tests/e2e/initialization/config.go @@ -22,6 +22,7 @@ import ( govv1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1" "github.com/classic-terra/core/v3/tests/e2e/util" + tax2gastypes "github.com/classic-terra/core/v3/x/tax2gas/types" treasurytypes "github.com/classic-terra/core/v3/x/treasury/types" ) @@ -44,7 +45,8 @@ const ( TerraDenom = "uluna" AtomDenom = "uatom" TerraIBCDenom = "ibc/4627AD2524E3E0523047E35BB76CC90E37D9D57ACF14F0FCBCEB2480705F3CB8" - MinGasPrice = "0.000" + MinGasPrice = "0.00000000001" + E10 = 10000000000 IbcSendAmount = 3300000000 ValidatorWalletName = "val" // chainA @@ -256,6 +258,11 @@ func initGenesis(chain *internalChain, forkHeight int) error { return err } + err = updateModuleGenesis(appGenState, tax2gastypes.ModuleName, &tax2gastypes.GenesisState{}, updateTax2GasGenesis) + if err != nil { + return err + } + bz, err := json.MarshalIndent(appGenState, "", " ") if err != nil { return err @@ -352,6 +359,15 @@ func updateGenUtilGenesis(c *internalChain) func(*genutiltypes.GenesisState) { } } +func updateTax2GasGenesis(tax2gasGenState *tax2gastypes.GenesisState) { + tax2gasGenState.Params.GasPrices = sdk.NewDecCoins( + // Gas prices will be very small so that normal tx only care about taxes + sdk.NewDecCoinFromDec("uluna", sdk.NewDecWithPrec(5, 11)), // 0.5 * 10^-10 + sdk.NewDecCoinFromDec("uusd", sdk.NewDecWithPrec(1, 10)), // 1 * 10^-10 + sdk.NewDecCoinFromDec("ueur", sdk.NewDecWithPrec(2, 10)), // 2 * 10^-10 + ) +} + func setDenomMetadata(genState *banktypes.GenesisState, denom string) { genState.DenomMetadata = append(genState.DenomMetadata, banktypes.Metadata{ Description: fmt.Sprintf("Registered denom %s for e2e testing", denom), diff --git a/tests/e2e/scripts/hermes_bootstrap.sh b/tests/e2e/scripts/hermes_bootstrap.sh index 0402f93ea..29a7c624f 100644 --- a/tests/e2e/scripts/hermes_bootstrap.sh +++ b/tests/e2e/scripts/hermes_bootstrap.sh @@ -42,8 +42,8 @@ account_prefix = 'terra' key_name = 'val01-terra-a' store_prefix = 'ibc' max_gas = 6000000 -gas_price = { price = 0.1, denom = 'uluna' } -gas_multiplier = 1.1 +gas_price = { price = 28.325, denom = 'uluna' } +gas_multiplier = 3 max_msg_num = 30 max_tx_size = 2097152 clock_drift = '5s' # to accomdate docker containers @@ -69,8 +69,8 @@ account_prefix = 'terra' key_name = 'val01-terra-b' store_prefix = 'ibc' max_gas = 6000000 -gas_price = { price = 0.1, denom = 'uluna' } -gas_multiplier = 1.1 +gas_price = { price = 28.325, denom = 'uluna' } +gas_multiplier = 3 max_msg_num = 30 max_tx_size = 2097152 clock_drift = '5s' # to accomdate docker containers diff --git a/tests/interchaintest/setup.go b/tests/interchaintest/setup.go index 336c0b389..00b826307 100644 --- a/tests/interchaintest/setup.go +++ b/tests/interchaintest/setup.go @@ -81,6 +81,10 @@ func ModifyGenesis() func(ibc.ChainConfig, []byte) ([]byte, error) { if err := dyno.Set(g, chainConfig.Denom, "app_state", "gov", "params", "min_deposit", 0, "denom"); err != nil { return nil, fmt.Errorf("failed to set voting period in genesis json: %w", err) } + // Disable tax2gas params to disable + if err := dyno.Set(g, false, "app_state", "tax2gas", "params", "enabled"); err != nil { + return nil, fmt.Errorf("failed to set tax2gas params in genesis json: %w", err) + } // Modify signed blocks window if err := dyno.Set(g, signedBlocksWindow, "app_state", "slashing", "params", "signed_blocks_window"); err != nil { return nil, fmt.Errorf("failed to set signed blocks window in genesis json: %w", err) diff --git a/x/tax2gas/README.md b/x/tax2gas/README.md new file mode 100644 index 000000000..f9d258a02 --- /dev/null +++ b/x/tax2gas/README.md @@ -0,0 +1,27 @@ +# Tax2gas + +## Testcases + +- Normal tx success +- Not supported tx will not be deducted tax amount +- Special IBC tx will be bypass when gas usage is not exceeded +- Forward tx should minus the amount to tx origin +- Multiple forward works +- Error forward tx should return the fund +- Out of gas should return the tax and not consumed gas +- Multiple msg types should works +- Grant msg should work +- Allow pay with multiple fees should work + +| No | Name | Scenario | Expect Result | Covered by | +|----|----------|-------------------|---------------|------------| +| 1 | Normal transaction should success | User transfer or make some special transactions which send coins to different address | Tax should be deducted with correct amount| [TestFeeTax](../../tests/e2e/e2e_test.go#L108)
[TestFeeTaxWasm](../../tests/e2e/e2e_test.go#L157)| +| 2 | Not supported tx will not be deducted tax amount | User transfer or make some special transactions that not in the tax list | Tax shouldn't be deducted with correct amount| | +| 3 | Special IBC tx will be bypass when gas limit is not exceeded | User make IBC transactions that happen both cases:
- Gas usage does not exceeded `maxTotalBypassMinFeeMsgGasUsage`
-Gas usage exceeded `maxTotalBypassMinFeeMsgGasUsage` | Bypass when gas limit not exceeded and deduct fee when exceed | | +| 4 | Forward transaction should deduct the amount to tx origin | User execute contract that will trigger an execute msg to another contract | - User should be the tx origin of the execute msg
- Tax should be deducted with correct amount | | +| 5 | Multiple forward works | Contracts will trigger another contracts multiple times | - User should be the tx origin of the execute msg
- Tax should be deducted with correct amount | | +| 6 | Error forward tx should return the tax and not consumed gas | User execute contract that will trigger an execute msg to another contract. The execute msg to another contract will be failed | Tax and not consumed gas should be revert to user | | +| 7 | Out of gas should return the tax and not consumed gas | User make some transactions with limited gas amount that will lead to cause `out of gas` error | Tax and not consumed gas should be revert to user | 🛑 Not figure out the way to make `out of gas` error occur, should be test in testnet | +| 8 | Multiple msg types should works | - Test multiple tx type that's in the tax list or not
- Contract dispatch multiple tx types | Chain will deduct tax with correct amount | | +| 9 | Grant msg should work | User grant multiple type of permissions to different transactions | Grant permission msg will only can deduct with one denom | [TestFeeTaxGrant](../../tests/e2e/e2e_test.go#L212) | +| 10 | Allow pay with multiple fees should work | User make transaction with multiple coins as fee | Fee can be paid by multiple denom, if one denom is not enough, then it will deduct other denom | | diff --git a/x/tax2gas/ante/ante.go b/x/tax2gas/ante/ante.go new file mode 100644 index 000000000..66dcabd0f --- /dev/null +++ b/x/tax2gas/ante/ante.go @@ -0,0 +1,287 @@ +package ante + +import ( + "fmt" + "math" + + tmstrings "github.com/cometbft/cometbft/libs/strings" + + 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" + tax2gasutils "github.com/classic-terra/core/v3/x/tax2gas/utils" +) + +// FeeDecorator deducts fees from the first signer of the tx +// If the first signer does not have the funds to pay for the fees, return with InsufficientFunds error +// Call next AnteHandler if fees successfully deducted +// CONTRACT: Tx must implement FeeTx interface to use DeductFeeDecorator +type FeeDecorator struct { + accountKeeper ante.AccountKeeper + bankKeeper types.BankKeeper + feegrantKeeper types.FeegrantKeeper + treasuryKeeper types.TreasuryKeeper + tax2gasKeeper tax2gasKeeper.Keeper +} + +func NewFeeDecorator(ak ante.AccountKeeper, bk types.BankKeeper, fk types.FeegrantKeeper, tk types.TreasuryKeeper, taxKeeper tax2gasKeeper.Keeper) FeeDecorator { + return FeeDecorator{ + accountKeeper: ak, + bankKeeper: bk, + feegrantKeeper: fk, + treasuryKeeper: tk, + tax2gasKeeper: taxKeeper, + } +} + +func (fd FeeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (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") + } + + var ( + priority int64 + err error + ) + + msgs := feeTx.GetMsgs() + if tax2gasutils.IsOracleTx(msgs) || simulate || !fd.tax2gasKeeper.IsEnabled(ctx) { + return next(ctx, tx, simulate) + } + + // Compute taxes based on consumed gas + gasPrices := fd.tax2gasKeeper.GetGasPrices(ctx) + gasConsumed := ctx.GasMeter().GasConsumed() + gasConsumedFees, err := tax2gasutils.ComputeFeesOnGasConsumed(tx, gasPrices, gasConsumed) + if err != nil { + return ctx, err + } + + // Compute taxes based on sent amount + taxes := tax2gasutils.FilterMsgAndComputeTax(ctx, fd.treasuryKeeper, msgs...) + // Convert taxes to gas + taxGas, err := tax2gasutils.ComputeGas(gasPrices, taxes) + if err != nil { + return ctx, err + } + + // Bypass min fee requires: + // - the tx contains only message types that can bypass the minimum fee, + // see BypassMinFeeMsgTypes; + // - the total gas limit per message does not exceed MaxTotalBypassMinFeeMsgGasUsage, + // i.e., totalGas <= MaxTotalBypassMinFeeMsgGasUsage + // Otherwise, minimum fees and global fees are checked to prevent spam. + maxTotalBypassMinFeeMsgGasUsage := fd.tax2gasKeeper.GetMaxTotalBypassMinFeeMsgGasUsage(ctx) + doesNotExceedMaxGasUsage := feeTx.GetGas() <= maxTotalBypassMinFeeMsgGasUsage + allBypassMsgs := fd.ContainsOnlyBypassMinFeeMsgs(ctx, msgs) + allowedToBypassMinFee := allBypassMsgs && doesNotExceedMaxGasUsage + + if allowedToBypassMinFee { + return next(ctx, tx, simulate) + } + + if feeTx.GetGas()-gasConsumed < taxGas { + return ctx, errorsmod.Wrap( + sdkerrors.ErrInvalidGasLimit, + fmt.Sprintf("must provide enough gas to cover taxes, gas limit(%d) - gas consumed(%d) < tax gas(%d)", + feeTx.GetGas(), gasConsumed, taxGas), + ) + } + + if !simulate && !taxes.IsZero() { + // Fee has to at least be enough to cover taxes + priority, err = fd.checkTxFee(ctx, tx, taxes) + if err != nil { + return ctx, err + } + } + + // Try to deduct the gasConsumed fees + paidDenom, err := fd.tryDeductFee(ctx, feeTx, gasConsumedFees) + if err != nil { + return ctx, err + } + + newCtx := ctx.WithPriority(priority).WithValue(types.TaxGas, taxGas) + if taxGas != 0 { + newCtx.TaxGasMeter().ConsumeGas(taxGas, "ante handler taxGas") + } + newCtx = newCtx.WithValue(types.AnteConsumedGas, gasConsumed) + if paidDenom != "" { + newCtx = newCtx.WithValue(types.PaidDenom, paidDenom) + } + + return next(newCtx, tx, simulate) +} + +func (fd FeeDecorator) tryDeductFee(ctx sdk.Context, feeTx sdk.FeeTx, taxes sdk.Coins) (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) + } + + feeCoins := feeTx.GetFee() + feePayer := feeTx.FeePayer() + feeGranter := feeTx.FeeGranter() + deductFeesFrom := feePayer + + foundCoins := sdk.Coins{} + if !taxes.IsZero() { + for _, coin := range feeCoins { + found, requiredFee := taxes.Find(coin.Denom) + if !found { + continue + } + if coin.Amount.GTE(requiredFee.Amount) { + foundCoins = foundCoins.Add(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") + } else if !feeGranter.Equals(feePayer) { + allowance, err := fd.feegrantKeeper.GetAllowance(ctx, feeGranter, feePayer) + if err != nil { + return "", errorsmod.Wrapf(err, "fee-grant not found with granter %s and grantee %s", feeGranter, feePayer) + } + + granted := false + for _, foundCoin := range foundCoins { + _, err := allowance.Accept(ctx, sdk.NewCoins(foundCoin), feeTx.GetMsgs()) + if err == nil { + foundCoins = sdk.NewCoins(foundCoin) + granted = true + err = fd.feegrantKeeper.UseGrantedFees(ctx, feeGranter, feePayer, foundCoins, feeTx.GetMsgs()) + if err != nil { + return "", errorsmod.Wrapf(err, "%s does not allow to pay fees for %s", feeGranter, feePayer) + } + break + } + } + + if !granted { + return "", errorsmod.Wrapf(err, "%s does not allow to pay fees for %s", feeGranter, feePayer) + } + } + + deductFeesFrom = feeGranter + } + + deductFeesFromAcc := fd.accountKeeper.GetAccount(ctx, deductFeesFrom) + if deductFeesFromAcc == nil { + return "", sdkerrors.ErrUnknownAddress.Wrapf("fee payer address: %s does not exist", deductFeesFrom) + } + + // deduct the fees + if !foundCoins.IsZero() { + foundCoins, err := DeductFees(fd.bankKeeper, ctx, deductFeesFromAcc, foundCoins) + if err != nil { + return "", err + } + + events := sdk.Events{ + sdk.NewEvent( + sdk.EventTypeTx, + sdk.NewAttribute(sdk.AttributeKeyFee, foundCoins.String()), + sdk.NewAttribute(sdk.AttributeKeyFeePayer, deductFeesFrom.String()), + ), + } + ctx.EventManager().EmitEvents(events) + + // As there is only 1 element + return foundCoins.Denoms()[0], nil + } + return "", fmt.Errorf("can't find coin that matches. Expected %s, wanted %s", feeCoins, taxes) +} + +// DeductFees deducts fees from the given account. +func DeductFees(bankKeeper types.BankKeeper, ctx sdk.Context, acc authtypes.AccountI, fees sdk.Coins) (sdk.Coins, error) { + if !fees.IsValid() { + return nil, errorsmod.Wrapf(sdkerrors.ErrInsufficientFee, "invalid fee amount: %s", fees) + } + + for _, fee := range fees { + balance := bankKeeper.GetBalance(ctx, acc.GetAddress(), fee.Denom) + if balance.IsGTE(fee) { + err := bankKeeper.SendCoinsFromAccountToModule(ctx, acc.GetAddress(), authtypes.FeeCollectorName, sdk.NewCoins(fee)) + if err != nil { + return nil, errorsmod.Wrapf(err, "failed to send fee to fee collector: %s", fee) + } + return sdk.NewCoins(fee), nil + } + } + + return nil, sdkerrors.ErrInsufficientFunds +} + +// checkTxFee implements the default fee logic, where the minimum price per +// unit of gas is fixed and set by each validator, can the tx priority is computed from the gas price. +// Transaction with only oracle messages will skip gas fee check and will have the most priority. +// It also checks enough fee for treasury tax +func (fd FeeDecorator) checkTxFee(ctx sdk.Context, tx sdk.Tx, taxes sdk.Coins) (int64, error) { + feeTx, ok := tx.(sdk.FeeTx) + if !ok { + return 0, errorsmod.Wrap(sdkerrors.ErrTxDecode, "Tx must be a FeeTx") + } + + feeCoins := feeTx.GetFee() + gas := feeTx.GetGas() + msgs := feeTx.GetMsgs() + isOracleTx := tax2gasutils.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 { + 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...) + + // Check required fees + if !requiredFees.IsZero() && !feeCoins.IsAnyGTE(requiredFees) { + return 0, errorsmod.Wrapf(sdkerrors.ErrInsufficientFee, "insufficient fees; got: %q, required: %q = %q(gas) + %q(stability)", feeCoins, requiredFees, requiredGasFees, taxes) + } + } + + priority := int64(math.MaxInt64) + + if !isOracleTx { + priority = tax2gasutils.GetTxPriority(feeCoins, int64(gas)) + } + + return priority, nil +} + +func (fd FeeDecorator) ContainsOnlyBypassMinFeeMsgs(ctx sdk.Context, msgs []sdk.Msg) bool { + bypassMsgTypes := fd.tax2gasKeeper.GetBypassMinFeeMsgTypes(ctx) + + for _, msg := range msgs { + if tmstrings.StringInSlice(sdk.MsgTypeURL(msg), bypassMsgTypes) { + continue + } + return false + } + + return true +} diff --git a/x/tax2gas/ante/ante_test.go b/x/tax2gas/ante/ante_test.go new file mode 100644 index 000000000..cf9da82ec --- /dev/null +++ b/x/tax2gas/ante/ante_test.go @@ -0,0 +1,131 @@ +package ante_test + +import ( + "testing" + + "github.com/stretchr/testify/suite" + + dbm "github.com/cometbft/cometbft-db" + "github.com/cometbft/cometbft/libs/log" + tmproto "github.com/cometbft/cometbft/proto/tendermint/types" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/tx" + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" + simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims" + "github.com/cosmos/cosmos-sdk/testutil/testdata" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/module/testutil" + "github.com/cosmos/cosmos-sdk/types/tx/signing" + xauthsigning "github.com/cosmos/cosmos-sdk/x/auth/signing" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + distributiontypes "github.com/cosmos/cosmos-sdk/x/distribution/types" + + wasmkeeper "github.com/CosmWasm/wasmd/x/wasm/keeper" + + terraapp "github.com/classic-terra/core/v3/app" + tax2gastypes "github.com/classic-terra/core/v3/x/tax2gas/types" + treasurytypes "github.com/classic-terra/core/v3/x/treasury/types" +) + +type AnteTestSuite struct { + suite.Suite + + app *terraapp.TerraApp + // anteHandler sdk.AnteHandler + ctx sdk.Context + clientCtx client.Context + txBuilder client.TxBuilder +} + +// returns context and app with params set on account keeper +func createTestApp(isCheckTx bool, tempDir string) (*terraapp.TerraApp, sdk.Context) { + // TODO: we need to feed in custom binding here? + var wasmOpts []wasmkeeper.Option + app := terraapp.NewTerraApp( + log.NewNopLogger(), dbm.NewMemDB(), nil, true, map[int64]bool{}, + tempDir, terraapp.MakeEncodingConfig(), + simtestutil.EmptyAppOptions{}, wasmOpts, + ) + ctx := app.BaseApp.NewContext(isCheckTx, tmproto.Header{}) + app.AccountKeeper.SetParams(ctx, authtypes.DefaultParams()) + app.TreasuryKeeper.SetParams(ctx, treasurytypes.DefaultParams()) + app.DistrKeeper.SetParams(ctx, distributiontypes.DefaultParams()) + app.DistrKeeper.SetFeePool(ctx, distributiontypes.InitialFeePool()) + app.Tax2gasKeeper.SetParams(ctx, tax2gastypes.DefaultParams()) + + return app, ctx +} + +// SetupTest setups a new test, with new app, context, and anteHandler. +func (suite *AnteTestSuite) SetupTest(isCheckTx bool) { + tempDir := suite.T().TempDir() + suite.app, suite.ctx = createTestApp(isCheckTx, tempDir) + suite.ctx = suite.ctx.WithBlockHeight(1) + + // Set up TxConfig. + encodingConfig := suite.SetupEncoding() + + suite.clientCtx = client.Context{}. + WithTxConfig(encodingConfig.TxConfig) +} + +func (suite *AnteTestSuite) SetupEncoding() testutil.TestEncodingConfig { + encodingConfig := testutil.MakeTestEncodingConfig() + // We're using TestMsg encoding in some tests, so register it here. + encodingConfig.Amino.RegisterConcrete(&testdata.TestMsg{}, "testdata.TestMsg", nil) + testdata.RegisterInterfaces(encodingConfig.InterfaceRegistry) + + return encodingConfig +} + +// CreateTestTx is a helper function to create a tx given multiple inputs. +func (suite *AnteTestSuite) CreateTestTx(privs []cryptotypes.PrivKey, accNums []uint64, accSeqs []uint64, chainID string) (xauthsigning.Tx, error) { + // First round: we gather all the signer infos. We use the "set empty + // signature" hack to do that. + var sigsV2 []signing.SignatureV2 + for i, priv := range privs { + sigV2 := signing.SignatureV2{ + PubKey: priv.PubKey(), + Data: &signing.SingleSignatureData{ + SignMode: suite.clientCtx.TxConfig.SignModeHandler().DefaultMode(), + Signature: nil, + }, + Sequence: accSeqs[i], + } + + sigsV2 = append(sigsV2, sigV2) + } + err := suite.txBuilder.SetSignatures(sigsV2...) + if err != nil { + return nil, err + } + + // Second round: all signer infos are set, so each signer can sign. + sigsV2 = []signing.SignatureV2{} + for i, priv := range privs { + signerData := xauthsigning.SignerData{ + ChainID: chainID, + AccountNumber: accNums[i], + Sequence: accSeqs[i], + } + sigV2, err := tx.SignWithPrivKey( + suite.clientCtx.TxConfig.SignModeHandler().DefaultMode(), signerData, + suite.txBuilder, priv, suite.clientCtx.TxConfig, accSeqs[i]) + if err != nil { + return nil, err + } + + sigsV2 = append(sigsV2, sigV2) + } + err = suite.txBuilder.SetSignatures(sigsV2...) + if err != nil { + return nil, err + } + + return suite.txBuilder.GetTx(), nil +} + +func TestAnteTestSuite(t *testing.T) { + suite.Run(t, new(AnteTestSuite)) +} diff --git a/x/tax2gas/ante/fee_test.go b/x/tax2gas/ante/fee_test.go new file mode 100644 index 000000000..f352e69f0 --- /dev/null +++ b/x/tax2gas/ante/fee_test.go @@ -0,0 +1,665 @@ +package ante_test + +import ( + "encoding/json" + "fmt" + "os" + "time" + + "cosmossdk.io/math" + wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types" + tmproto "github.com/cometbft/cometbft/proto/tendermint/types" + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" + "github.com/cosmos/cosmos-sdk/testutil/testdata" + sdk "github.com/cosmos/cosmos-sdk/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" + + 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" + "github.com/classic-terra/core/v3/x/tax2gas/ante" + + ibcclienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" + ibcchanneltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" + ibctesting "github.com/cosmos/ibc-go/v7/testing" + + wasmkeeper "github.com/CosmWasm/wasmd/x/wasm/keeper" +) + +var ( + sendCoin = sdk.NewInt64Coin(core.MicroLunaDenom, int64(1000000)) + sendCoins = sdk.NewCoins(sendCoin) +) + +func (s *AnteTestSuite) TestDeductFeeDecorator() { + s.SetupTest(true) // setup + s.txBuilder = s.clientCtx.TxConfig.NewTxBuilder() + + mfd := ante.NewFeeDecorator(s.app.AccountKeeper, s.app.BankKeeper, s.app.FeeGrantKeeper, s.app.TreasuryKeeper, s.app.Tax2gasKeeper) + 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) + + privs, accNums, accSeqs := []cryptotypes.PrivKey{priv1}, []uint64{0}, []uint64{0} + tx, err := s.CreateTestTx(privs, accNums, accSeqs, s.ctx.ChainID()) + s.Require().NoError(err) + + testCases := []struct { + name string + simulation bool + checkTx bool + mallate func() + expFail bool + expErrMsg string + }{ + { + name: "success: zero gas in simulation", + simulation: true, + checkTx: true, + mallate: func() { + // set zero gas + s.txBuilder.SetGasLimit(0) + }, + expFail: false, + }, + { + name: "Success: deduct sufficient fees", + simulation: false, + checkTx: true, + mallate: func() { + msg := testdata.NewTestMsg(addr1) + s.Require().NoError(s.txBuilder.SetMsgs(msg)) + // GasConsumed : 7220*28.325 = 204507 + err = testutil.FundAccount(s.app.BankKeeper, s.ctx, addr1, sdk.NewCoins(sdk.NewCoin(core.MicroLunaDenom, sdk.NewInt(204507)))) + feeAmount := sdk.NewCoins(sdk.NewInt64Coin(core.MicroLunaDenom, 204507)) + s.txBuilder.SetFeeAmount(feeAmount) + s.txBuilder.SetGasLimit(100000) + }, + expFail: false, + }, + { + name: "Fail: deduct insufficient fees", + simulation: false, + checkTx: true, + mallate: func() { + msg := testdata.NewTestMsg(addr1) + s.Require().NoError(s.txBuilder.SetMsgs(msg)) + // GasConsumed : 7220*28,325 = 204507 + err = testutil.FundAccount(s.app.BankKeeper, s.ctx, addr1, sdk.NewCoins(sdk.NewCoin(core.MicroLunaDenom, sdk.NewInt(204506)))) + feeAmount := sdk.NewCoins(sdk.NewInt64Coin(core.MicroLunaDenom, 204506)) + s.txBuilder.SetFeeAmount(feeAmount) + s.txBuilder.SetGasLimit(100000) + }, + expFail: true, + expErrMsg: "can't find coin", + }, + { + name: "Success: Instantiate contract", + simulation: false, + checkTx: true, + mallate: func() { + msg := &wasmtypes.MsgInstantiateContract{ + Sender: addr1.String(), + Admin: addr1.String(), + CodeID: 0, + Msg: []byte{}, + Funds: sendCoins, + } + s.Require().NoError(s.txBuilder.SetMsgs(msg)) + // Consumed gas at the point of ante is: 7220 but the gas limit is 100000 + // 100000*28.325 (gas fee) + 1000 (tax) = 2833500 + err = testutil.FundAccount(s.app.BankKeeper, s.ctx, addr1, sdk.NewCoins(sdk.NewCoin(core.MicroLunaDenom, sdk.NewInt(2833500)))) + feeAmount := sdk.NewCoins(sdk.NewInt64Coin(core.MicroLunaDenom, 2833500)) + s.txBuilder.SetFeeAmount(feeAmount) + s.txBuilder.SetGasLimit(100000) + }, + expFail: false, + }, + { + name: "Success: Instantiate2 contract", + simulation: false, + checkTx: true, + mallate: func() { + msg := &wasmtypes.MsgInstantiateContract2{ + Sender: addr1.String(), + Admin: addr1.String(), + CodeID: 0, + Msg: []byte{}, + Funds: sendCoins, + } + // Consumed gas at the point of ante is: 7220 but the gas limit is 100000 + // 100000*28.325 (gas fee) + 1000 (tax) = 2833500 + s.Require().NoError(s.txBuilder.SetMsgs(msg)) + err = testutil.FundAccount(s.app.BankKeeper, s.ctx, addr1, sdk.NewCoins(sdk.NewCoin(core.MicroLunaDenom, sdk.NewInt(2833500)))) + feeAmount := sdk.NewCoins(sdk.NewInt64Coin(core.MicroLunaDenom, 2833500)) + s.txBuilder.SetFeeAmount(feeAmount) + s.txBuilder.SetGasLimit(100000) + }, + expFail: false, + }, + { + name: "Fail: Instantiate2 contract insufficient fees", + simulation: false, + checkTx: true, + mallate: func() { + msg := &wasmtypes.MsgInstantiateContract2{ + Sender: addr1.String(), + Admin: addr1.String(), + CodeID: 0, + Msg: []byte{}, + Funds: sendCoins, + } + // Consumed gas at the point of ante is: 7220 but the gas limit is 100000 + // 100000*28.325 (gas fee) + 1000 (tax) = 2833500 + s.Require().NoError(s.txBuilder.SetMsgs(msg)) + err = testutil.FundAccount(s.app.BankKeeper, s.ctx, addr1, sdk.NewCoins(sdk.NewCoin(core.MicroLunaDenom, sdk.NewInt(2833499)))) + feeAmount := sdk.NewCoins(sdk.NewInt64Coin(core.MicroLunaDenom, 2833499)) + s.txBuilder.SetFeeAmount(feeAmount) + s.txBuilder.SetGasLimit(100000) + }, + expFail: true, + expErrMsg: "insufficient fees", + }, + { + name: "Success: Execute contract", + simulation: false, + checkTx: true, + mallate: func() { + msg := &wasmtypes.MsgExecuteContract{ + Sender: addr1.String(), + Contract: addr1.String(), + Msg: []byte{}, + Funds: sendCoins, + } + // Consumed gas at the point of ante is: 7220 but the gas limit is 100000 + // 100000*28.325 (gas fee) + 1000 (tax) = 2833500 + s.Require().NoError(s.txBuilder.SetMsgs(msg)) + err = testutil.FundAccount(s.app.BankKeeper, s.ctx, addr1, sdk.NewCoins(sdk.NewCoin(core.MicroLunaDenom, sdk.NewInt(2833500)))) + feeAmount := sdk.NewCoins(sdk.NewInt64Coin(core.MicroLunaDenom, 2833500)) + + s.txBuilder.SetFeeAmount(feeAmount) + s.txBuilder.SetGasLimit(100000) + }, + expFail: false, + }, + { + name: "Success: Bank send", + simulation: false, + checkTx: true, + mallate: func() { + msg := banktypes.NewMsgSend(addr1, addr1, sendCoins) + // Consumed gas at the point of ante is: 7220 but the gas limit is 100000 + // 100000*28.325 (gas fee) + 1000 (tax) = 2833500 + s.Require().NoError(s.txBuilder.SetMsgs(msg)) + err = testutil.FundAccount(s.app.BankKeeper, s.ctx, addr1, sdk.NewCoins(sdk.NewCoin(core.MicroLunaDenom, sdk.NewInt(2833500)))) + feeAmount := sdk.NewCoins(sdk.NewInt64Coin(core.MicroLunaDenom, 2833500)) + + s.txBuilder.SetFeeAmount(feeAmount) + s.txBuilder.SetGasLimit(100000) + }, + expFail: false, + }, + { + name: "Success: Bank multisend", + simulation: false, + checkTx: true, + mallate: func() { + msg := banktypes.NewMsgMultiSend( + []banktypes.Input{ + banktypes.NewInput(addr1, sendCoins), + banktypes.NewInput(addr1, sendCoins), + }, + []banktypes.Output{ + banktypes.NewOutput(addr1, sendCoins), + banktypes.NewOutput(addr1, sendCoins), + }) + // Consumed gas at the point of ante is: 7220 but the gas limit is 100000 + // 100000*28.325 (gas fee) + 2000 (tax) = 2834500 + s.Require().NoError(s.txBuilder.SetMsgs(msg)) + err = testutil.FundAccount(s.app.BankKeeper, s.ctx, addr1, sdk.NewCoins(sdk.NewCoin(core.MicroLunaDenom, sdk.NewInt(2834500)))) + feeAmount := sdk.NewCoins(sdk.NewInt64Coin(core.MicroLunaDenom, 2834500)) + s.txBuilder.SetFeeAmount(feeAmount) + s.txBuilder.SetGasLimit(100000) + }, + expFail: false, + }, + { + name: "Success: Market swapsend", + simulation: false, + checkTx: true, + mallate: func() { + msg := markettypes.NewMsgSwapSend(addr1, addr1, sendCoin, core.MicroKRWDenom) + // Consumed gas at the point of ante is: 7220 but the gas limit is 100000 + // 100000*28.325 (gas fee) + 1000 (tax) = 2833500 + s.Require().NoError(s.txBuilder.SetMsgs(msg)) + err = testutil.FundAccount(s.app.BankKeeper, s.ctx, addr1, sdk.NewCoins(sdk.NewCoin(core.MicroLunaDenom, sdk.NewInt(2833500)))) + feeAmount := sdk.NewCoins(sdk.NewInt64Coin(core.MicroLunaDenom, 2833500)) + s.txBuilder.SetFeeAmount(feeAmount) + s.txBuilder.SetGasLimit(100000) + }, + expFail: false, + }, + { + name: "Success: Authz exec", + simulation: false, + checkTx: true, + mallate: func() { + msg := authz.NewMsgExec(addr1, []sdk.Msg{banktypes.NewMsgSend(addr1, addr1, sendCoins)}) + // Consumed gas at the point of ante is: 7220 but the gas limit is 100000 + // 100000*28.325 (gas fee) + 1000 (tax) = 2833500 + s.Require().NoError(s.txBuilder.SetMsgs(&msg)) + err = testutil.FundAccount(s.app.BankKeeper, s.ctx, addr1, sdk.NewCoins(sdk.NewCoin(core.MicroLunaDenom, sdk.NewInt(2833500)))) + feeAmount := sdk.NewCoins(sdk.NewInt64Coin(core.MicroLunaDenom, 2833500)) + s.txBuilder.SetFeeAmount(feeAmount) + s.txBuilder.SetGasLimit(100000) + }, + expFail: false, + }, + { + + name: "Fail: Authz exec", + simulation: false, + checkTx: true, + mallate: func() { + msg := authz.NewMsgExec(addr1, []sdk.Msg{banktypes.NewMsgSend(addr1, addr1, sendCoins)}) + // Consumed gas at the point of ante is: 7220 but the gas limit is 100000 + // 100000*28.325 (gas fee) + 1000 (tax) = 2833500 + s.Require().NoError(s.txBuilder.SetMsgs(&msg)) + err = testutil.FundAccount(s.app.BankKeeper, s.ctx, addr1, sdk.NewCoins(sdk.NewCoin(core.MicroLunaDenom, sdk.NewInt(2833500)))) + feeAmount := sdk.NewCoins(sdk.NewInt64Coin(core.MicroLunaDenom, 2833500)) + s.txBuilder.SetFeeAmount(feeAmount) + s.txBuilder.SetGasLimit(100000) + }, + expFail: false, + }, + { + + name: "Bypass: ibc MsgRecvPacket", + simulation: false, + checkTx: true, + mallate: func() { + msg := ibcchanneltypes.NewMsgRecvPacket( + ibcchanneltypes.Packet{}, + []byte(""), + ibcclienttypes.ZeroHeight(), + addr1.String(), + ) + s.Require().NoError(s.txBuilder.SetMsgs(msg)) + feeAmount := sdk.NewCoins(sdk.NewInt64Coin(core.MicroLunaDenom, 0)) + s.txBuilder.SetFeeAmount(feeAmount) + s.txBuilder.SetGasLimit(1_000_000) + }, + expFail: false, + }, + { + + name: "Not Bypass: ibc MsgRecvPacket", + simulation: false, + checkTx: true, + mallate: func() { + msg := ibcchanneltypes.NewMsgRecvPacket( + ibcchanneltypes.Packet{}, + []byte(""), + ibcclienttypes.ZeroHeight(), + addr1.String(), + ) + s.Require().NoError(s.txBuilder.SetMsgs(msg)) + feeAmount := sdk.NewCoins(sdk.NewInt64Coin(core.MicroLunaDenom, 0)) + s.txBuilder.SetFeeAmount(feeAmount) + s.txBuilder.SetGasLimit(1_000_001) + }, + expFail: true, + expErrMsg: "can't find coin", + }, + { + + name: "Bypass: ibc MsgAcknowledgement", + simulation: false, + checkTx: true, + mallate: func() { + msg := ibcchanneltypes.NewMsgAcknowledgement( + ibcchanneltypes.Packet{}, + []byte(""), + []byte(""), + ibcclienttypes.ZeroHeight(), + addr1.String(), + ) + s.Require().NoError(s.txBuilder.SetMsgs(msg)) + feeAmount := sdk.NewCoins(sdk.NewInt64Coin(core.MicroLunaDenom, 0)) + s.txBuilder.SetFeeAmount(feeAmount) + s.txBuilder.SetGasLimit(1_000_000) + }, + expFail: false, + }, + { + + name: "Bypass: ibc MsgUpdateClient", + simulation: false, + checkTx: true, + mallate: func() { + soloMachine := ibctesting.NewSolomachine(s.T(), s.app.AppCodec(), "solomachine", "", 2) + msg, err := ibcclienttypes.NewMsgUpdateClient( + soloMachine.ClientID, + soloMachine.CreateHeader(soloMachine.Diversifier), + string(addr1), + ) + s.Require().NoError(err) + s.Require().NoError(s.txBuilder.SetMsgs(msg)) + feeAmount := sdk.NewCoins(sdk.NewInt64Coin(core.MicroLunaDenom, 0)) + s.txBuilder.SetFeeAmount(feeAmount) + s.txBuilder.SetGasLimit(1_000_000) + }, + expFail: false, + }, + { + + name: "Bypass: ibc MsgTimeout", + simulation: false, + checkTx: true, + mallate: func() { + msg := ibcchanneltypes.NewMsgTimeout( + ibcchanneltypes.Packet{}, + 1, + []byte(""), + ibcclienttypes.ZeroHeight(), + addr1.String(), + ) + s.Require().NoError(s.txBuilder.SetMsgs(msg)) + feeAmount := sdk.NewCoins(sdk.NewInt64Coin(core.MicroLunaDenom, 0)) + s.txBuilder.SetFeeAmount(feeAmount) + s.txBuilder.SetGasLimit(1_000_000) + }, + expFail: false, + }, + { + + name: "Bypass: ibc MsgTimeoutOnClose", + simulation: false, + checkTx: true, + mallate: func() { + msg := ibcchanneltypes.NewMsgTimeoutOnClose( + ibcchanneltypes.Packet{}, + 1, + []byte(""), + []byte(""), + ibcclienttypes.ZeroHeight(), + addr1.String(), + ) + s.Require().NoError(s.txBuilder.SetMsgs(msg)) + feeAmount := sdk.NewCoins(sdk.NewInt64Coin(core.MicroLunaDenom, 0)) + s.txBuilder.SetFeeAmount(feeAmount) + s.txBuilder.SetGasLimit(1_000_000) + }, + expFail: false, + }, + { + + name: "Other msgs must pay gas fee", + simulation: false, + checkTx: true, + mallate: func() { + msg := stakingtypes.NewMsgDelegate( + addr1, + sdk.ValAddress(addr1), + sdk.NewCoin(core.MicroLunaDenom, math.NewInt(100000)), + ) + s.Require().NoError(s.txBuilder.SetMsgs(msg)) + feeAmount := sdk.NewCoins(sdk.NewInt64Coin(core.MicroLunaDenom, 0)) + s.txBuilder.SetFeeAmount(feeAmount) + s.txBuilder.SetGasLimit(1_000_000) + }, + expFail: true, + expErrMsg: "can't find coin", + }, + { + + name: "Oracle zero fee", + simulation: false, + checkTx: true, + mallate: func() { + val, err := stakingtypes.NewValidator(sdk.ValAddress(addr1), priv1.PubKey(), stakingtypes.Description{}) + s.Require().NoError(err) + + msg := oracletypes.NewMsgAggregateExchangeRatePrevote( + oracletypes.GetAggregateVoteHash("salt", "exchange rates", val.GetOperator()), + addr1, + val.GetOperator(), + ) + s.Require().NoError(s.txBuilder.SetMsgs(msg)) + feeAmount := sdk.NewCoins(sdk.NewInt64Coin(core.MicroLunaDenom, 0)) + s.txBuilder.SetFeeAmount(feeAmount) + s.txBuilder.SetGasLimit(1_000_000) + }, + expFail: false, + }, + } + + for _, tc := range testCases { + tc := tc + s.Run(tc.name, func() { + tc.mallate() + s.ctx = s.app.BaseApp.NewContext(tc.checkTx, tmproto.Header{}) + + _, err = antehandler(s.ctx, tx, tc.simulation) + + if tc.expFail { + s.Require().Error(err) + s.Require().Contains(err.Error(), tc.expErrMsg) + } else { + s.Require().NoError(err) + } + }) + } +} + +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.MicroLunaDenom, sendAmt) + feeAmt := int64(1000) + + cases := []struct { + name string + msgSigner cryptotypes.PrivKey + msgCreator func() []sdk.Msg + minFeeAmount 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 + }, + // 263025*28.325 = 7450184 - only gas fee + minFeeAmount: 7450184, + }, { + 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: 7450184 + 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: 7450184 + 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: 7450184 + 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: 7450184 + 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 + }, + // 1046653*28.325 = 29646447 + minFeeAmount: 29646447 + feeAmt, + }, + } + + // there should be no coin in burn module + for _, c := range cases { + s.SetupTest(true) // setup + require := s.Require() + tk := s.app.TreasuryKeeper + 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 := ante.NewFeeDecorator(s.app.AccountKeeper, s.app.BankKeeper, s.app.FeeGrantKeeper, s.app.TreasuryKeeper, s.app.Tax2gasKeeper) + antehandler := sdk.ChainAnteDecorators(mfd) + + for i := 0; i < 4; i++ { + coins := sdk.NewCoins(sdk.NewCoin(core.MicroLunaDenom, sdk.NewInt(100000000000))) + testutil.FundAccount(s.app.BankKeeper, s.ctx, addrs[i], coins) + } + + // msg and signatures + feeAmount := sdk.NewCoins(sdk.NewInt64Coin(core.MicroLunaDenom, 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) + } +} diff --git a/custom/auth/ante/testdata/hackatom.wasm b/x/tax2gas/ante/testdata/hackatom.wasm similarity index 100% rename from custom/auth/ante/testdata/hackatom.wasm rename to x/tax2gas/ante/testdata/hackatom.wasm diff --git a/x/tax2gas/client/cli/query.go b/x/tax2gas/client/cli/query.go new file mode 100644 index 000000000..fffdca4c1 --- /dev/null +++ b/x/tax2gas/client/cli/query.go @@ -0,0 +1,59 @@ +package cli + +import ( + "context" + "fmt" + + "github.com/spf13/cobra" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/flags" + + "github.com/classic-terra/core/v3/x/tax2gas/types" +) + +// GetQueryCmd returns the cli query commands for this module +func GetQueryCmd() *cobra.Command { + tax2gasQueryCmd := &cobra.Command{ + Use: types.ModuleName, + Short: fmt.Sprintf("Querying commands for the %s module", types.ModuleName), + DisableFlagParsing: true, + SuggestionsMinimumDistance: 2, + RunE: client.ValidateCmd, + } + + tax2gasQueryCmd.AddCommand( + GetCmdQueryParams(), + ) + + return tax2gasQueryCmd +} + +// GetCmdQueryParams implements a command to return the current parameters. +func GetCmdQueryParams() *cobra.Command { + cmd := &cobra.Command{ + Use: "params", + Short: "Query the current tax2gas module parameters", + Args: cobra.NoArgs, + RunE: func(cmd *cobra.Command, _ []string) error { + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + queryClient := types.NewQueryClient(clientCtx) + + params := &types.QueryParamsRequest{} + + res, err := queryClient.Params(context.Background(), params) + if err != nil { + return err + } + + return clientCtx.PrintProto(&res.Params) + }, + } + + flags.AddQueryFlagsToCmd(cmd) + + return cmd +} diff --git a/x/tax2gas/client/cli/tx.go b/x/tax2gas/client/cli/tx.go new file mode 100644 index 000000000..53254c471 --- /dev/null +++ b/x/tax2gas/client/cli/tx.go @@ -0,0 +1,21 @@ +package cli + +import ( + "github.com/spf13/cobra" + + "github.com/cosmos/cosmos-sdk/client" + + "github.com/classic-terra/core/v3/x/tax2gas/types" +) + +// NewTxCmd returns a root CLI command handler for certain modules transaction commands. +func NewTxCmd() *cobra.Command { + txCmd := &cobra.Command{ + Use: types.ModuleName, + Short: "tax2gas subcommands", + DisableFlagParsing: true, + SuggestionsMinimumDistance: 2, + RunE: client.ValidateCmd, + } + return txCmd +} 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/keeper.go b/x/tax2gas/keeper/keeper.go new file mode 100644 index 000000000..2b1655c45 --- /dev/null +++ b/x/tax2gas/keeper/keeper.go @@ -0,0 +1,79 @@ +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" + + "github.com/classic-terra/core/v3/x/tax2gas/types" +) + +type Keeper struct { + storeKey storetypes.StoreKey + cdc codec.BinaryCodec + + // the address capable of executing a MsgUpdateParams message. Typically, this + // should be the x/gov module account. + authority string +} + +func NewKeeper( + cdc codec.BinaryCodec, + storeKey storetypes.StoreKey, + authority string, +) Keeper { + if _, err := sdk.AccAddressFromBech32(authority); err != nil { + panic(fmt.Errorf("invalid bank authority address: %w", err)) + } + + return Keeper{cdc: cdc, storeKey: storeKey, authority: authority} +} + +// 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 { + panic(err) + } + + k.SetParams(ctx, genState.Params) +} + +// ExportGenesis returns the tax2gas module's exported genesis. +func (k Keeper) ExportGenesis(ctx sdk.Context) *types.GenesisState { + return &types.GenesisState{ + Params: k.GetParams(ctx), + } +} + +// 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)) +} + +// GetAuthority returns the x/tax2gas module's authority. +func (k Keeper) GetAuthority() string { + return k.authority +} + +func (k Keeper) IsEnabled(ctx sdk.Context) bool { + return k.GetParams(ctx).Enabled +} + +func (k Keeper) GetGasPrices(ctx sdk.Context) sdk.DecCoins { + return k.GetParams(ctx).GasPrices.Sort() +} + +// GetBypassMinFeeMsgTypes gets the tax2gas module's BypassMinFeeMsgTypes. +func (k Keeper) GetBypassMinFeeMsgTypes(ctx sdk.Context) []string { + return k.GetParams(ctx).BypassMinFeeMsgTypes +} + +// GetBypassMinFeeMsgTypes gets the tax2gas module's BypassMinFeeMsgTypes. +func (k Keeper) GetMaxTotalBypassMinFeeMsgGasUsage(ctx sdk.Context) uint64 { + return k.GetParams(ctx).MaxTotalBypassMinFeeMsgGasUsage +} diff --git a/x/tax2gas/keeper/keeper_test.go b/x/tax2gas/keeper/keeper_test.go new file mode 100644 index 000000000..0ac9f8372 --- /dev/null +++ b/x/tax2gas/keeper/keeper_test.go @@ -0,0 +1,119 @@ +package keeper_test + +import ( + "testing" + + "github.com/classic-terra/core/v3/x/tax2gas/keeper" + "github.com/classic-terra/core/v3/x/tax2gas/types" + "github.com/cosmos/cosmos-sdk/testutil" + sdk "github.com/cosmos/cosmos-sdk/types" + moduletestutil "github.com/cosmos/cosmos-sdk/types/module/testutil" + "github.com/stretchr/testify/suite" + + tmproto "github.com/cometbft/cometbft/proto/tendermint/types" + tmtime "github.com/cometbft/cometbft/types/time" + "github.com/cosmos/cosmos-sdk/baseapp" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + minttypes "github.com/cosmos/cosmos-sdk/x/mint/types" +) + +type KeeperTestSuite struct { + suite.Suite + + ctx sdk.Context + keeper keeper.Keeper + + queryClient types.QueryClient + msgServer types.MsgServer + + encCfg moduletestutil.TestEncodingConfig +} + +func TestKeeperTestSuite(t *testing.T) { + suite.Run(t, new(KeeperTestSuite)) +} + +func (suite *KeeperTestSuite) SetupTest() { + key := sdk.NewKVStoreKey(types.StoreKey) + testCtx := testutil.DefaultContextWithDB(suite.T(), key, sdk.NewTransientStoreKey("transient_test")) + ctx := testCtx.Ctx.WithBlockHeader(tmproto.Header{Time: tmtime.Now()}) + encCfg := moduletestutil.MakeTestEncodingConfig() + + // gomock initializations + + suite.ctx = ctx + suite.keeper = keeper.NewKeeper( + encCfg.Codec, + key, + authtypes.NewModuleAddress(govtypes.ModuleName).String(), + ) + + types.RegisterInterfaces(encCfg.InterfaceRegistry) + + queryHelper := baseapp.NewQueryServerTestHelper(ctx, encCfg.InterfaceRegistry) + types.RegisterQueryServer(queryHelper, suite.keeper) + queryClient := types.NewQueryClient(queryHelper) + + suite.queryClient = queryClient + suite.msgServer = keeper.NewMsgServerImpl(suite.keeper) + suite.encCfg = encCfg +} + +func (suite *KeeperTestSuite) TestGetAuthority() { + NewKeeperWithAuthority := func(authority string) keeper.Keeper { + return keeper.NewKeeper( + moduletestutil.MakeTestEncodingConfig().Codec, + sdk.NewKVStoreKey(types.StoreKey), + authority, + ) + } + + tests := map[string]string{ + "some random account": "cosmos139f7kncmglres2nf3h4hc4tade85ekfr8sulz5", + "gov module account": authtypes.NewModuleAddress(govtypes.ModuleName).String(), + "another module account": authtypes.NewModuleAddress(minttypes.ModuleName).String(), + } + + for name, expected := range tests { + suite.T().Run(name, func(t *testing.T) { + kpr := NewKeeperWithAuthority(expected) + actual := kpr.GetAuthority() + suite.Require().Equal(expected, actual) + }) + } +} + +func (suite *KeeperTestSuite) TestSetParams() { + ctx, tax2gasKeeper := suite.ctx, suite.keeper + require := suite.Require() + + tax2gasKeeper.SetParams(ctx, types.DefaultParams()) + tests := []struct { + name string + params types.Params + expFail bool + }{ + { + name: "empty params", + params: types.Params{}, + expFail: true, + }, + { + name: "default params", + params: types.DefaultParams(), + expFail: false, + }, + } + + for _, tc := range tests { + suite.T().Run(tc.name, func(t *testing.T) { + err := tax2gasKeeper.SetParams(ctx, tc.params) + if tc.expFail { + require.Error(err) + } else { + require.NoError(err) + } + }) + } +} diff --git a/x/tax2gas/keeper/msg_server.go b/x/tax2gas/keeper/msg_server.go new file mode 100644 index 000000000..2bfff7a50 --- /dev/null +++ b/x/tax2gas/keeper/msg_server.go @@ -0,0 +1,36 @@ +package keeper + +import ( + "context" + + errorsmod "cosmossdk.io/errors" + sdk "github.com/cosmos/cosmos-sdk/types" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + + "github.com/classic-terra/core/v3/x/tax2gas/types" +) + +type msgServer struct { + Keeper +} + +var _ types.MsgServer = msgServer{} + +// NewMsgServerImpl returns an implementation of the tax2gas MsgServer interface +// for the provided Keeper. +func NewMsgServerImpl(keeper Keeper) types.MsgServer { + return &msgServer{Keeper: keeper} +} + +func (k msgServer) UpdateParams(goCtx context.Context, req *types.MsgUpdateParams) (*types.MsgUpdateParamsResponse, error) { + if k.GetAuthority() != req.Authority { + return nil, errorsmod.Wrapf(govtypes.ErrInvalidSigner, "invalid authority; expected %s, got %s", k.GetAuthority(), req.Authority) + } + + ctx := sdk.UnwrapSDKContext(goCtx) + if err := k.SetParams(ctx, req.Params); err != nil { + return nil, err + } + + return &types.MsgUpdateParamsResponse{}, nil +} diff --git a/x/tax2gas/keeper/msg_server_test.go b/x/tax2gas/keeper/msg_server_test.go new file mode 100644 index 000000000..3819954fc --- /dev/null +++ b/x/tax2gas/keeper/msg_server_test.go @@ -0,0 +1,58 @@ +package keeper_test + +import ( + "github.com/classic-terra/core/v3/x/tax2gas/types" +) + +func (suite *KeeperTestSuite) TestMsgUpdateParams() { + // default params + params := types.DefaultParams() + + testCases := []struct { + name string + input *types.MsgUpdateParams + expErr bool + expErrMsg string + }{ + { + name: "invalid authority", + input: &types.MsgUpdateParams{ + Authority: "invalid", + Params: params, + }, + expErr: true, + expErrMsg: "invalid authority", + }, + { + name: "empty params", + input: &types.MsgUpdateParams{ + Authority: suite.keeper.GetAuthority(), + Params: types.Params{}, + }, + expErr: true, + expErrMsg: "must provide at least 1 gas prices", + }, + { + name: "all good", + input: &types.MsgUpdateParams{ + Authority: suite.keeper.GetAuthority(), + Params: params, + }, + expErr: false, + }, + } + + for _, tc := range testCases { + tc := tc + suite.Run(tc.name, func() { + _, err := suite.msgServer.UpdateParams(suite.ctx, tc.input) + + if tc.expErr { + suite.Require().Error(err) + suite.Require().Contains(err.Error(), tc.expErrMsg) + } else { + suite.Require().NoError(err) + } + }) + } +} diff --git a/x/tax2gas/keeper/params.go b/x/tax2gas/keeper/params.go new file mode 100644 index 000000000..d36ab16e1 --- /dev/null +++ b/x/tax2gas/keeper/params.go @@ -0,0 +1,34 @@ +package keeper + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/classic-terra/core/v3/x/tax2gas/types" +) + +// SetParams sets the tax2gas module's parameters. +func (k Keeper) SetParams(ctx sdk.Context, params types.Params) error { + if err := params.Validate(); err != nil { + return err + } + 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 tax2gas 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..77db022a0 --- /dev/null +++ b/x/tax2gas/keeper/querier.go @@ -0,0 +1,17 @@ +package keeper + +import ( + "context" + + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/classic-terra/core/v3/x/tax2gas/types" +) + +var _ types.QueryServer = Keeper{} + +// Params queries params of dyncomm module +func (k Keeper) Params(c context.Context, _ *types.QueryParamsRequest) (*types.QueryParamsResponse, error) { + ctx := sdk.UnwrapSDKContext(c) + return &types.QueryParamsResponse{Params: k.GetParams(ctx)}, nil +} diff --git a/x/tax2gas/keeper/querier_test.go b/x/tax2gas/keeper/querier_test.go new file mode 100644 index 000000000..d4d3d04b1 --- /dev/null +++ b/x/tax2gas/keeper/querier_test.go @@ -0,0 +1,14 @@ +package keeper_test + +import ( + "context" + + "github.com/classic-terra/core/v3/x/tax2gas/types" +) + +func (suite *KeeperTestSuite) TestQueryParams() { + res, err := suite.queryClient.Params(context.Background(), &types.QueryParamsRequest{}) + suite.Require().NoError(err) + suite.Require().NotNil(res) + suite.Require().Equal(suite.keeper.GetParams(suite.ctx), res.GetParams()) +} diff --git a/x/tax2gas/module.go b/x/tax2gas/module.go new file mode 100644 index 000000000..e34c9764b --- /dev/null +++ b/x/tax2gas/module.go @@ -0,0 +1,122 @@ +package module + +import ( + "context" + "encoding/json" + "fmt" + + abci "github.com/cometbft/cometbft/abci/types" + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/codec" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/module" + "github.com/grpc-ecosystem/grpc-gateway/runtime" + "github.com/spf13/cobra" + + "github.com/classic-terra/core/v3/x/tax2gas/client/cli" + "github.com/classic-terra/core/v3/x/tax2gas/keeper" + "github.com/classic-terra/core/v3/x/tax2gas/types" +) + +var ( + _ module.AppModule = AppModule{} + _ module.AppModuleBasic = AppModuleBasic{} +) + +type AppModuleBasic struct { + cdc codec.Codec +} + +func (AppModuleBasic) Name() string { return types.ModuleName } + +func (AppModuleBasic) RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { + types.RegisterLegacyAminoCodec(cdc) +} + +func (AppModuleBasic) DefaultGenesis(cdc codec.JSONCodec) json.RawMessage { + return cdc.MustMarshalJSON(types.DefaultGenesis()) +} + +// ValidateGenesis performs genesis state validation for the tax2gas module. +func (AppModuleBasic) ValidateGenesis(cdc codec.JSONCodec, _ client.TxEncodingConfig, bz json.RawMessage) error { + var genState types.GenesisState + if err := cdc.UnmarshalJSON(bz, &genState); err != nil { + return fmt.Errorf("failed to unmarshal %s genesis state: %w", types.ModuleName, err) + } + return genState.Validate() +} + +// --------------------------------------- +// Interfaces. +func (b AppModuleBasic) RegisterGRPCGatewayRoutes(clientCtx client.Context, mux *runtime.ServeMux) { + if err := types.RegisterQueryHandlerClient(context.Background(), mux, types.NewQueryClient(clientCtx)); err != nil { + panic(err) + } +} + +func (b AppModuleBasic) GetTxCmd() *cobra.Command { + return cli.NewTxCmd() +} + +func (b AppModuleBasic) GetQueryCmd() *cobra.Command { + return cli.GetQueryCmd() +} + +// RegisterInterfaces registers interfaces and implementations of the tax2gas module. +func (AppModuleBasic) RegisterInterfaces(registry codectypes.InterfaceRegistry) { + types.RegisterInterfaces(registry) +} + +type AppModule struct { + AppModuleBasic + + k keeper.Keeper +} + +func (am AppModule) RegisterServices(cfg module.Configurator) { + types.RegisterMsgServer(cfg.MsgServer(), keeper.NewMsgServerImpl(am.k)) + // queryproto.RegisterQueryServer(cfg.QueryServer(), grpc.Querier{Q: module.NewQuerier(am.k)}) + types.RegisterQueryServer(cfg.QueryServer(), am.k) +} + +func NewAppModule(cdc codec.Codec, tax2gasKeeper keeper.Keeper) AppModule { + return AppModule{ + AppModuleBasic: AppModuleBasic{cdc}, + k: tax2gasKeeper, + } +} + +func (am AppModule) RegisterInvariants(_ sdk.InvariantRegistry) { +} + +// QuerierRoute returns the tax2gas module's querier route name. +func (AppModule) QuerierRoute() string { return types.RouterKey } + +// 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) + InitGenesis(ctx, am.k, &genesisState) + return []abci.ValidatorUpdate{} +} + +// 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) + return cdc.MustMarshalJSON(genState) +} + +// BeginBlock performs TODO. +func (AppModule) BeginBlock(_ sdk.Context, _ abci.RequestBeginBlock) {} + +// EndBlock performs TODO. +func (am AppModule) EndBlock(_ sdk.Context, _ abci.RequestEndBlock) []abci.ValidatorUpdate { + return []abci.ValidatorUpdate{} +} + +// ConsensusVersion implements AppModule/ConsensusVersion. +func (AppModule) ConsensusVersion() uint64 { return 1 } diff --git a/x/tax2gas/post/burntax.go b/x/tax2gas/post/burntax.go new file mode 100644 index 000000000..c59381112 --- /dev/null +++ b/x/tax2gas/post/burntax.go @@ -0,0 +1,96 @@ +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/types" + + oracle "github.com/classic-terra/core/v3/x/oracle/types" + treasury "github.com/classic-terra/core/v3/x/treasury/types" + distributiontypes "github.com/cosmos/cosmos-sdk/x/distribution/types" +) + +// BurnTaxSplit splits +func (fd Tax2gasPostDecorator) BurnTaxSplit(ctx sdk.Context, taxes sdk.Coins) (err error) { + burnSplitRate := fd.treasuryKeeper.GetBurnSplitRate(ctx) + oracleSplitRate := fd.treasuryKeeper.GetOracleSplitRate(ctx) + communityTax := fd.distrKeeper.GetCommunityTax(ctx) + distributionDeltaCoins := sdk.NewCoins() + oracleSplitCoins := sdk.NewCoins() + communityTaxCoins := sdk.NewCoins() + + if burnSplitRate.IsPositive() { + + for _, taxCoin := range taxes { + splitcoinAmount := burnSplitRate.MulInt(taxCoin.Amount).RoundInt() + distributionDeltaCoins = distributionDeltaCoins.Add(sdk.NewCoin(taxCoin.Denom, splitcoinAmount)) + } + + taxes = taxes.Sub(distributionDeltaCoins...) + } + + if communityTax.IsPositive() { + + // we need to apply a reduced community tax here as the community tax is applied again during distribution + // in the distribution module and we don't want to calculate the tax twice + // the reduction depends on the oracle split rate as well as on the community tax itself + // the formula can be applied even with a zero oracle split rate + applyCommunityTax := communityTax.Mul(oracleSplitRate.Quo(communityTax.Mul(oracleSplitRate).Add(sdk.OneDec()).Sub(communityTax))) + + for _, distrCoin := range distributionDeltaCoins { + communityTaxAmount := applyCommunityTax.MulInt(distrCoin.Amount).RoundInt() + communityTaxCoins = communityTaxCoins.Add(sdk.NewCoin(distrCoin.Denom, communityTaxAmount)) + } + + distributionDeltaCoins = distributionDeltaCoins.Sub(communityTaxCoins...) + } + + if !communityTaxCoins.IsZero() { + if err = fd.bankKeeper.SendCoinsFromModuleToModule( + ctx, + types.FeeCollectorName, + distributiontypes.ModuleName, + communityTaxCoins, + ); err != nil { + return errorsmod.Wrapf(sdkerrors.ErrInsufficientFunds, err.Error()) + } + + feePool := fd.distrKeeper.GetFeePool(ctx) + feePool.CommunityPool = feePool.CommunityPool.Add(sdk.NewDecCoinsFromCoins(communityTaxCoins...)...) + fd.distrKeeper.SetFeePool(ctx, feePool) + } + + if oracleSplitRate.IsPositive() { + for _, distrCoin := range distributionDeltaCoins { + oracleCoinAmnt := oracleSplitRate.MulInt(distrCoin.Amount).RoundInt() + oracleSplitCoins = oracleSplitCoins.Add(sdk.NewCoin(distrCoin.Denom, oracleCoinAmnt)) + } + } + + if !oracleSplitCoins.IsZero() { + if err = fd.bankKeeper.SendCoinsFromModuleToModule( + ctx, + types.FeeCollectorName, + oracle.ModuleName, + oracleSplitCoins, + ); err != nil { + return errorsmod.Wrapf(sdkerrors.ErrInsufficientFunds, err.Error()) + } + } + + if !taxes.IsZero() { + if err = fd.bankKeeper.SendCoinsFromModuleToModule( + ctx, + types.FeeCollectorName, + treasury.BurnModuleName, + taxes, + ); err != nil { + return errorsmod.Wrapf(sdkerrors.ErrInsufficientFunds, err.Error()) + } + } + + // Record tax proceeds + fd.treasuryKeeper.RecordEpochTaxProceeds(ctx, taxes) + return nil +} diff --git a/x/tax2gas/post/post.go b/x/tax2gas/post/post.go new file mode 100644 index 000000000..1d09428e3 --- /dev/null +++ b/x/tax2gas/post/post.go @@ -0,0 +1,152 @@ +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" + tax2gasutils "github.com/classic-terra/core/v3/x/tax2gas/utils" +) + +type Tax2gasPostDecorator struct { + accountKeeper ante.AccountKeeper + bankKeeper types.BankKeeper + feegrantKeeper types.FeegrantKeeper + treasuryKeeper types.TreasuryKeeper + distrKeeper types.DistrKeeper + tax2gasKeeper tax2gasKeeper.Keeper +} + +func NewTax2GasPostDecorator(accountKeeper ante.AccountKeeper, bankKeeper types.BankKeeper, feegrantKeeper types.FeegrantKeeper, treasuryKeeper types.TreasuryKeeper, distrKeeper types.DistrKeeper, tax2gasKeeper tax2gasKeeper.Keeper) Tax2gasPostDecorator { + return Tax2gasPostDecorator{ + accountKeeper: accountKeeper, + bankKeeper: bankKeeper, + feegrantKeeper: feegrantKeeper, + treasuryKeeper: treasuryKeeper, + distrKeeper: distrKeeper, + tax2gasKeeper: tax2gasKeeper, + } +} + +// TODO: handle fail tx +func (tgd 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") + } + msgs := feeTx.GetMsgs() + if tax2gasutils.IsOracleTx(msgs) || simulate || !tgd.tax2gasKeeper.IsEnabled(ctx) { + return next(ctx, tx, simulate, success) + } + + feeCoins := feeTx.GetFee() + anteConsumedGas, ok := ctx.Value(types.AnteConsumedGas).(uint64) + if !ok { + // If cannot found the anteConsumedGas, that's mean the tx is bypass + // Skip this tx as it's bypass + return next(ctx, tx, simulate, success) + } + + // Get paid denom identified in ante handler + paidDenom, ok := ctx.Value(types.PaidDenom).(string) + if !ok { + // If cannot found the paidDenom, that's mean this is the init genesis tx + // Skip this tx as it's init genesis tx + return next(ctx, tx, simulate, success) + } + + gasPrices := tgd.tax2gasKeeper.GetGasPrices(ctx) + found, paidDenomGasPrice := tax2gasutils.GetGasPriceByDenom(gasPrices, paidDenom) + if !found { + return ctx, types.ErrDenomNotFound + } + paidAmount := paidDenomGasPrice.Mul(sdk.NewDec(int64(anteConsumedGas))) + // Deduct feeCoins with paid amount + feeCoins = feeCoins.Sub(sdk.NewCoin(paidDenom, paidAmount.Ceil().RoundInt())) + + taxGas := ctx.TaxGasMeter().GasConsumed() + + // we consume the gas here as we need to calculate the tax for consumed gas + ctx.GasMeter().ConsumeGas(taxGas, "tax gas") + + totalGasConsumed := ctx.GasMeter().GasConsumed() + // Deduct the gas consumed amount spent on ante handler + totalGasRemaining := totalGasConsumed - anteConsumedGas + + feePayer := feeTx.FeePayer() + feeGranter := feeTx.FeeGranter() + + // if feegranter set deduct fee from feegranter account. + // this works with only when feegrant enabled. + if feeGranter != nil { + if tgd.feegrantKeeper == nil { + return ctx, sdkerrors.ErrInvalidRequest.Wrap("fee grants are not enabled") + } else if !feeGranter.Equals(feePayer) { + allowance, err := tgd.feegrantKeeper.GetAllowance(ctx, feeGranter, feePayer) + if err != nil { + return ctx, errorsmod.Wrapf(err, "fee-grant not found with granter %s and grantee %s", feeGranter, feePayer) + } + + gasRemainingFees, err := tax2gasutils.ComputeFeesOnGasConsumed(tx, gasPrices, totalGasRemaining) + if err != nil { + return ctx, err + } + + // For this tx, we only accept to pay by one denom + for _, feeRequired := range gasRemainingFees { + _, err := allowance.Accept(ctx, sdk.NewCoins(feeRequired), feeTx.GetMsgs()) + if err == nil { + err = tgd.feegrantKeeper.UseGrantedFees(ctx, feeGranter, feePayer, sdk.NewCoins(feeRequired), feeTx.GetMsgs()) + if err != nil { + return ctx, errorsmod.Wrapf(err, "%s does not allow to pay fees for %s", feeGranter, feePayer) + } + feeGranter := tgd.accountKeeper.GetAccount(ctx, feeGranter) + err = tgd.bankKeeper.SendCoinsFromAccountToModule(ctx, feeGranter.GetAddress(), authtypes.FeeCollectorName, sdk.NewCoins(feeRequired)) + if err != nil { + return ctx, errorsmod.Wrapf(sdkerrors.ErrInsufficientFunds, err.Error()) + } + + // Calculate tax fee and BurnTaxSplit + _, gasPrice := tax2gasutils.GetGasPriceByDenom(gasPrices, feeRequired.Denom) + taxFee := gasPrice.MulInt64(int64(taxGas)).Ceil().RoundInt() + if !simulate { + err := tgd.BurnTaxSplit(ctx, sdk.NewCoins(sdk.NewCoin(feeRequired.Denom, taxFee))) + if err != nil { + return ctx, err + } + } + return next(ctx, tx, simulate, success) + } + } + return ctx, errorsmod.Wrapf(err, "%s does not allow to pay fees for %s", feeGranter, feePayer) + } + } + + // First, we will deduct the fees covered taxGas and handle BurnTaxSplit + taxes, payableFees, gasRemaining := tax2gasutils.CalculateTaxesAndPayableFee(gasPrices, feeCoins, taxGas, totalGasRemaining) + if gasRemaining > 0 { + return ctx, errorsmod.Wrapf(sdkerrors.ErrInsufficientFee, "fees are not enough to pay for gas, need to cover %d gas more", totalGasRemaining) + } + feePayerAccount := tgd.accountKeeper.GetAccount(ctx, feePayer) + err := tgd.bankKeeper.SendCoinsFromAccountToModule(ctx, feePayerAccount.GetAddress(), authtypes.FeeCollectorName, payableFees) + if err != nil { + return ctx, errorsmod.Wrapf(sdkerrors.ErrInsufficientFunds, err.Error()) + } + + if !simulate { + err := tgd.BurnTaxSplit(ctx, taxes) + if err != nil { + return ctx, err + } + } + + return next(ctx, tx, simulate, success) +} diff --git a/x/tax2gas/types/codec.go b/x/tax2gas/types/codec.go new file mode 100644 index 000000000..cffb8f985 --- /dev/null +++ b/x/tax2gas/types/codec.go @@ -0,0 +1,39 @@ +package types + +import ( + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/codec/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/msgservice" + authzcodec "github.com/cosmos/cosmos-sdk/x/authz/codec" +) + +// RegisterLegacyAminoCodec registers the necessary x/tax2gas interfaces and concrete types +// on the provided LegacyAmino codec. These types are used for Amino JSON serialization. +func RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { + cdc.RegisterConcrete(&MsgUpdateParams{}, "terra/tax2gas/MsgUpdateParams", nil) +} + +func RegisterInterfaces(registry types.InterfaceRegistry) { + registry.RegisterImplementations( + (*sdk.Msg)(nil), + &MsgUpdateParams{}, + ) + + msgservice.RegisterMsgServiceDesc(registry, &_Msg_serviceDesc) +} + +var ( + amino = codec.NewLegacyAmino() + ModuleCdc = codec.NewAminoCodec(amino) +) + +func init() { + RegisterLegacyAminoCodec(amino) + // Register all Amino interfaces and concrete types on the authz Amino codec so that this can later be + // used to properly serialize MsgGrant and MsgExec instances + sdk.RegisterLegacyAminoCodec(amino) + RegisterLegacyAminoCodec(authzcodec.Amino) + + amino.Seal() +} diff --git a/x/tax2gas/types/errors.go b/x/tax2gas/types/errors.go new file mode 100644 index 000000000..501df004d --- /dev/null +++ b/x/tax2gas/types/errors.go @@ -0,0 +1,12 @@ +package types + +import ( + errorsmod "cosmossdk.io/errors" +) + +// Tax2Gas errors +var ( + ErrParsing = errorsmod.Register(ModuleName, 1, "Parsing errors") + ErrCoinNotFound = errorsmod.Register(ModuleName, 2, "Coin not found") + ErrDenomNotFound = errorsmod.Register(ModuleName, 3, "Denom not found") +) diff --git a/x/tax2gas/types/events.go b/x/tax2gas/types/events.go new file mode 100644 index 000000000..885a885a7 --- /dev/null +++ b/x/tax2gas/types/events.go @@ -0,0 +1,5 @@ +package types + +const ( + AttributeValueCategory = ModuleName +) diff --git a/x/tax2gas/types/expected_keeper.go b/x/tax2gas/types/expected_keeper.go new file mode 100644 index 000000000..38f414f6d --- /dev/null +++ b/x/tax2gas/types/expected_keeper.go @@ -0,0 +1,42 @@ +package types + +import ( + "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/feegrant" + distributiontypes "github.com/cosmos/cosmos-sdk/x/distribution/types" +) + +// 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 + GetOracleSplitRate(ctx sdk.Context) sdk.Dec +} + +// BankKeeper defines the contract needed for supply related APIs (noalias) +type BankKeeper interface { + GetBalance(ctx sdk.Context, addr sdk.AccAddress, denom string) sdk.Coin + 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 + SendCoinsFromModuleToAccount(ctx sdk.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins) error +} + +type FeegrantKeeper interface { + GetAllowance(ctx sdk.Context, granter, grantee sdk.AccAddress) (feegrant.FeeAllowanceI, error) + UseGrantedFees(ctx sdk.Context, granter, grantee sdk.AccAddress, fee sdk.Coins, msgs []sdk.Msg) error +} + +type DistrKeeper interface { + FundCommunityPool(ctx sdk.Context, amount sdk.Coins, sender sdk.AccAddress) error + GetFeePool(ctx sdk.Context) distributiontypes.FeePool + GetCommunityTax(ctx sdk.Context) math.LegacyDec + SetFeePool(ctx sdk.Context, feePool distributiontypes.FeePool) +} diff --git a/x/tax2gas/types/genesis.go b/x/tax2gas/types/genesis.go new file mode 100644 index 000000000..964a1a3ea --- /dev/null +++ b/x/tax2gas/types/genesis.go @@ -0,0 +1,17 @@ +package types + +// DefaultGenesis returns the default tax2gas genesis state. +func DefaultGenesis() *GenesisState { + return &GenesisState{ + Params: DefaultParams(), + } +} + +// Validate performs basic genesis state validation returning an error upon any +// failure. +func (gs GenesisState) Validate() error { + if err := gs.Params.Validate(); err != nil { + return err + } + return nil +} diff --git a/x/tax2gas/types/genesis.pb.go b/x/tax2gas/types/genesis.pb.go new file mode 100644 index 000000000..524624d74 --- /dev/null +++ b/x/tax2gas/types/genesis.pb.go @@ -0,0 +1,661 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: terra/tax2gas/v1beta1/genesis.proto + +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/cosmos-sdk/types/tx/amino" + _ "github.com/cosmos/gogoproto/gogoproto" + proto "github.com/cosmos/gogoproto/proto" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +type Params struct { + GasPrices github_com_cosmos_cosmos_sdk_types.DecCoins `protobuf:"bytes,1,rep,name=gas_prices,json=gasPrices,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.DecCoins" json:"gas_prices" yaml:"gas_prices"` + Enabled bool `protobuf:"varint,2,opt,name=enabled,proto3" json:"enabled,omitempty"` + // bypass_min_fee_msg_types defines a list of message type urls + // that are free of fee charge. + BypassMinFeeMsgTypes []string `protobuf:"bytes,3,rep,name=bypass_min_fee_msg_types,json=bypassMinFeeMsgTypes,proto3" json:"bypass_min_fee_msg_types,omitempty" yaml:"bypass_min_fee_msg_types"` + // max_total_bypass_min_fee_msg_gas_usage defines the total maximum gas usage + // allowed for a transaction containing only messages of types in bypass_min_fee_msg_types + // to bypass fee charge. + MaxTotalBypassMinFeeMsgGasUsage uint64 `protobuf:"varint,4,opt,name=max_total_bypass_min_fee_msg_gas_usage,json=maxTotalBypassMinFeeMsgGasUsage,proto3" json:"max_total_bypass_min_fee_msg_gas_usage,omitempty"` +} + +func (m *Params) Reset() { *m = Params{} } +func (m *Params) String() string { return proto.CompactTextString(m) } +func (*Params) ProtoMessage() {} +func (*Params) Descriptor() ([]byte, []int) { + return fileDescriptor_589c4ef0e5113034, []int{0} +} +func (m *Params) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Params) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Params.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *Params) XXX_Merge(src proto.Message) { + xxx_messageInfo_Params.Merge(m, src) +} +func (m *Params) XXX_Size() int { + return m.Size() +} +func (m *Params) XXX_DiscardUnknown() { + xxx_messageInfo_Params.DiscardUnknown(m) +} + +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 +} + +func (m *Params) GetEnabled() bool { + if m != nil { + return m.Enabled + } + return false +} + +func (m *Params) GetBypassMinFeeMsgTypes() []string { + if m != nil { + return m.BypassMinFeeMsgTypes + } + return nil +} + +func (m *Params) GetMaxTotalBypassMinFeeMsgGasUsage() uint64 { + if m != nil { + return m.MaxTotalBypassMinFeeMsgGasUsage + } + return 0 +} + +// GenesisState defines the tax2gas module's genesis state. +type GenesisState struct { + // params is the container of tax2gas parameters. + Params Params `protobuf:"bytes,1,opt,name=params,proto3" json:"params"` +} + +func (m *GenesisState) Reset() { *m = GenesisState{} } +func (m *GenesisState) String() string { return proto.CompactTextString(m) } +func (*GenesisState) ProtoMessage() {} +func (*GenesisState) Descriptor() ([]byte, []int) { + return fileDescriptor_589c4ef0e5113034, []int{1} +} +func (m *GenesisState) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *GenesisState) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_GenesisState.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *GenesisState) XXX_Merge(src proto.Message) { + xxx_messageInfo_GenesisState.Merge(m, src) +} +func (m *GenesisState) XXX_Size() int { + return m.Size() +} +func (m *GenesisState) XXX_DiscardUnknown() { + xxx_messageInfo_GenesisState.DiscardUnknown(m) +} + +var xxx_messageInfo_GenesisState proto.InternalMessageInfo + +func (m *GenesisState) GetParams() Params { + if m != nil { + return m.Params + } + return Params{} +} + +func init() { + proto.RegisterType((*Params)(nil), "terra.tax2gas.v1beta1.Params") + proto.RegisterType((*GenesisState)(nil), "terra.tax2gas.v1beta1.GenesisState") +} + +func init() { + proto.RegisterFile("terra/tax2gas/v1beta1/genesis.proto", fileDescriptor_589c4ef0e5113034) +} + +var fileDescriptor_589c4ef0e5113034 = []byte{ + // 477 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x92, 0x3f, 0x6f, 0xd4, 0x4c, + 0x10, 0xc6, 0x6f, 0xdf, 0x3b, 0xdd, 0x4b, 0x1c, 0x9a, 0x58, 0x01, 0x59, 0x11, 0xd8, 0x96, 0x91, + 0x90, 0x15, 0x88, 0x97, 0x5c, 0xba, 0xd0, 0x19, 0x44, 0x04, 0xe8, 0x44, 0x64, 0x42, 0x43, 0x63, + 0x8d, 0x9d, 0x65, 0x59, 0x71, 0xeb, 0xb5, 0x3c, 0x9b, 0xe8, 0xae, 0xa4, 0x4d, 0x45, 0x49, 0x49, + 0x83, 0x84, 0xa8, 0xf2, 0x31, 0x52, 0xa6, 0xa4, 0x3a, 0xd0, 0x5d, 0x11, 0x89, 0x32, 0x9f, 0x00, + 0xd9, 0xeb, 0x0b, 0x41, 0x4a, 0x1a, 0xff, 0xd9, 0xf9, 0x3d, 0xcf, 0x8e, 0x66, 0x1e, 0xeb, 0x9e, + 0x66, 0x55, 0x05, 0x54, 0xc3, 0x78, 0xc0, 0x01, 0xe9, 0xe1, 0x66, 0xc6, 0x34, 0x6c, 0x52, 0xce, + 0x0a, 0x86, 0x02, 0xa3, 0xb2, 0x52, 0x5a, 0xd9, 0xb7, 0x1a, 0x28, 0x6a, 0xa1, 0xa8, 0x85, 0xd6, + 0x56, 0xb9, 0xe2, 0xaa, 0x21, 0x68, 0xfd, 0x65, 0xe0, 0x35, 0x37, 0x57, 0x28, 0x15, 0xd2, 0x0c, + 0x90, 0x5d, 0xf8, 0xe5, 0x4a, 0x14, 0x6d, 0x7d, 0x05, 0xa4, 0x28, 0x14, 0x6d, 0x9e, 0xe6, 0x28, + 0xf8, 0xda, 0xb5, 0xfa, 0xbb, 0x50, 0x81, 0x44, 0xfb, 0x88, 0x58, 0x16, 0x07, 0x4c, 0xcb, 0x4a, + 0xe4, 0x0c, 0x1d, 0xe2, 0x77, 0xc3, 0xe5, 0xc1, 0x9d, 0xc8, 0x78, 0x46, 0xb5, 0xe7, 0xe2, 0xfa, + 0xe8, 0x29, 0xcb, 0x9f, 0x28, 0x51, 0xc4, 0xc3, 0x93, 0xa9, 0xd7, 0x39, 0x9f, 0x7a, 0x2b, 0x13, + 0x90, 0xa3, 0xed, 0xe0, 0xaf, 0x3a, 0xf8, 0xfe, 0xd3, 0x7b, 0xc0, 0x85, 0x7e, 0x7f, 0x90, 0x45, + 0xb9, 0x92, 0xb4, 0x6d, 0xcc, 0xbc, 0x36, 0x70, 0xff, 0x03, 0xd5, 0x93, 0x92, 0xe1, 0xc2, 0x08, + 0xbf, 0x9d, 0x1d, 0xaf, 0x93, 0x64, 0x89, 0x03, 0xee, 0x36, 0x7a, 0xdb, 0xb1, 0xfe, 0x67, 0x05, + 0x64, 0x23, 0xb6, 0xef, 0xfc, 0xe7, 0x93, 0xf0, 0x46, 0xb2, 0xf8, 0xb5, 0x3f, 0x12, 0xcb, 0xc9, + 0x26, 0x25, 0x20, 0xa6, 0x52, 0x14, 0xe9, 0x3b, 0xc6, 0x52, 0x89, 0x3c, 0x6d, 0xfc, 0x9c, 0xae, + 0xdf, 0x0d, 0x97, 0xe2, 0xe7, 0xbf, 0xa7, 0x5e, 0x70, 0x1d, 0xf3, 0x50, 0x49, 0xa1, 0x99, 0x2c, + 0xf5, 0xe4, 0x7c, 0xea, 0x79, 0xa6, 0xf1, 0xeb, 0xd8, 0x20, 0x59, 0x35, 0xa5, 0xa1, 0x28, 0x9e, + 0x31, 0x36, 0x44, 0xbe, 0x57, 0x1f, 0xdb, 0xaf, 0xac, 0xfb, 0x12, 0xc6, 0xa9, 0x56, 0x1a, 0x46, + 0xe9, 0x15, 0xe2, 0x7a, 0x10, 0x07, 0x08, 0x9c, 0x39, 0x3d, 0x9f, 0x84, 0xbd, 0xc4, 0x93, 0x30, + 0xde, 0xab, 0xe1, 0xf8, 0x5f, 0xb7, 0x1d, 0xc0, 0x37, 0x35, 0xb6, 0xed, 0x7d, 0xfe, 0xe2, 0x91, + 0xa3, 0xb3, 0xe3, 0xf5, 0xdb, 0x26, 0x14, 0xe3, 0x8b, 0x58, 0x98, 0xe5, 0x04, 0x2f, 0xad, 0x9b, + 0x3b, 0x26, 0x18, 0xaf, 0x35, 0x68, 0x66, 0x3f, 0xb6, 0xfa, 0x65, 0x53, 0x71, 0x88, 0x4f, 0xc2, + 0xe5, 0xc1, 0xdd, 0xe8, 0xca, 0xa0, 0x44, 0x46, 0x1e, 0xf7, 0xea, 0x45, 0x25, 0xad, 0x24, 0x7e, + 0x71, 0x32, 0x73, 0xc9, 0xe9, 0xcc, 0x25, 0xbf, 0x66, 0x2e, 0xf9, 0x34, 0x77, 0x3b, 0xa7, 0x73, + 0xb7, 0xf3, 0x63, 0xee, 0x76, 0xde, 0x3e, 0xba, 0xbc, 0xb3, 0x11, 0x20, 0x8a, 0x7c, 0xc3, 0x74, + 0x94, 0xab, 0x8a, 0xd1, 0xc3, 0xad, 0x4b, 0x9d, 0x35, 0x13, 0xca, 0xfa, 0x4d, 0x8e, 0xb6, 0xfe, + 0x04, 0x00, 0x00, 0xff, 0xff, 0xb3, 0x61, 0x7e, 0x53, 0xce, 0x02, 0x00, 0x00, +} + +func (m *Params) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *Params) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Params) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.MaxTotalBypassMinFeeMsgGasUsage != 0 { + i = encodeVarintGenesis(dAtA, i, uint64(m.MaxTotalBypassMinFeeMsgGasUsage)) + i-- + dAtA[i] = 0x20 + } + if len(m.BypassMinFeeMsgTypes) > 0 { + for iNdEx := len(m.BypassMinFeeMsgTypes) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.BypassMinFeeMsgTypes[iNdEx]) + copy(dAtA[i:], m.BypassMinFeeMsgTypes[iNdEx]) + i = encodeVarintGenesis(dAtA, i, uint64(len(m.BypassMinFeeMsgTypes[iNdEx]))) + i-- + dAtA[i] = 0x1a + } + } + if m.Enabled { + i-- + if m.Enabled { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x10 + } + 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] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *GenesisState) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *GenesisState) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *GenesisState) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.Params.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func encodeVarintGenesis(dAtA []byte, offset int, v uint64) int { + offset -= sovGenesis(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *Params) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.GasPrices) > 0 { + for _, e := range m.GasPrices { + l = e.Size() + n += 1 + l + sovGenesis(uint64(l)) + } + } + if m.Enabled { + n += 2 + } + if len(m.BypassMinFeeMsgTypes) > 0 { + for _, s := range m.BypassMinFeeMsgTypes { + l = len(s) + n += 1 + l + sovGenesis(uint64(l)) + } + } + if m.MaxTotalBypassMinFeeMsgGasUsage != 0 { + n += 1 + sovGenesis(uint64(m.MaxTotalBypassMinFeeMsgGasUsage)) + } + return n +} + +func (m *GenesisState) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.Params.Size() + n += 1 + l + sovGenesis(uint64(l)) + return n +} + +func sovGenesis(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozGenesis(x uint64) (n int) { + return sovGenesis(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *Params) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: Params: wiretype end group for non-group") + } + if fieldNum <= 0 { + 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 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 + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Enabled", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.Enabled = bool(v != 0) + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field BypassMinFeeMsgTypes", 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 + } + m.BypassMinFeeMsgTypes = append(m.BypassMinFeeMsgTypes, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field MaxTotalBypassMinFeeMsgGasUsage", wireType) + } + m.MaxTotalBypassMinFeeMsgGasUsage = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.MaxTotalBypassMinFeeMsgGasUsage |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipGenesis(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenesis + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *GenesisState) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: GenesisState: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: GenesisState: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Params", 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 + } + if err := m.Params.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenesis(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenesis + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipGenesis(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowGenesis + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowGenesis + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowGenesis + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthGenesis + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupGenesis + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthGenesis + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthGenesis = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowGenesis = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupGenesis = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/tax2gas/types/keys.go b/x/tax2gas/types/keys.go new file mode 100644 index 000000000..0e1052e73 --- /dev/null +++ b/x/tax2gas/types/keys.go @@ -0,0 +1,20 @@ +package types + +const ( + ModuleName = "tax2gas" + + StoreKey = ModuleName + + RouterKey = ModuleName + + AnteConsumedGas = "anteConsumedGas" + + TaxGas = "taxGas" + + PaidDenom = "paidDenom" +) + +// Key defines the store key for tax2gas. +var ( + ParamsKey = []byte{0x1} +) diff --git a/x/tax2gas/types/msgs.go b/x/tax2gas/types/msgs.go new file mode 100644 index 000000000..b0b3e5b48 --- /dev/null +++ b/x/tax2gas/types/msgs.go @@ -0,0 +1,26 @@ +package types + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" +) + +const ( + TypeMsgUpdateParams = "update_params" +) + +var _ sdk.Msg = &MsgUpdateParams{} + +func (msg MsgUpdateParams) Route() string { return ModuleName } +func (msg MsgUpdateParams) Type() string { return TypeMsgUpdateParams } +func (msg MsgUpdateParams) ValidateBasic() error { + return msg.Params.Validate() +} + +func (msg MsgUpdateParams) GetSignBytes() []byte { + return sdk.MustSortJSON(ModuleCdc.MustMarshalJSON(&msg)) +} + +func (msg MsgUpdateParams) GetSigners() []sdk.AccAddress { + authority, _ := sdk.AccAddressFromBech32(msg.Authority) + return []sdk.AccAddress{authority} +} diff --git a/x/tax2gas/types/params.go b/x/tax2gas/types/params.go new file mode 100644 index 000000000..7b93ed110 --- /dev/null +++ b/x/tax2gas/types/params.go @@ -0,0 +1,81 @@ +package types + +import ( + fmt "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + + ibcclienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" + ibcchanneltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" +) + +var ( + // DefaultMinGasPrices is set at runtime to the staking token with zero amount i.e. "0uatom" + // see DefaultZeroGlobalFee method in gaia/x/globalfee/ante/fee.go. + DefaultGasPrices = 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)), + ) + DefaultBypassMinFeeMsgTypes = []string{ + sdk.MsgTypeURL(&ibcclienttypes.MsgUpdateClient{}), + sdk.MsgTypeURL(&ibcchanneltypes.MsgRecvPacket{}), + sdk.MsgTypeURL(&ibcchanneltypes.MsgAcknowledgement{}), + sdk.MsgTypeURL(&ibcchanneltypes.MsgTimeout{}), + sdk.MsgTypeURL(&ibcchanneltypes.MsgTimeoutOnClose{}), + } + + // maxTotalBypassMinFeeMsgGasUsage is the allowed maximum gas usage + // for all the bypass msgs in a transactions. + // A transaction that contains only bypass message types and the gas usage does not + // exceed maxTotalBypassMinFeeMsgGasUsage can be accepted with a zero fee. + // For details, see gaiafeeante.NewFeeDecorator() + DefaultmaxTotalBypassMinFeeMsgGasUsage uint64 = 1_000_000 +) + +func NewParams() Params { + return Params{} +} + +// DefaultParams are the default tax2gas module parameters. +func DefaultParams() Params { + return Params{ + GasPrices: DefaultGasPrices, + Enabled: true, + BypassMinFeeMsgTypes: DefaultBypassMinFeeMsgTypes, + MaxTotalBypassMinFeeMsgGasUsage: DefaultmaxTotalBypassMinFeeMsgGasUsage, + } +} + +// Validate validates params. +func (p Params) Validate() error { + if p.Enabled { + if len(p.GasPrices) == 0 { + return fmt.Errorf("must provide at least 1 gas prices") + } + if !p.GasPrices.IsAllPositive() { + return fmt.Errorf("gas prices must be positive") + } + } + return nil +} diff --git a/x/tax2gas/types/query.pb.go b/x/tax2gas/types/query.pb.go new file mode 100644 index 000000000..9597dd1a5 --- /dev/null +++ b/x/tax2gas/types/query.pb.go @@ -0,0 +1,532 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: terra/tax2gas/v1beta1/query.proto + +package types + +import ( + context "context" + fmt "fmt" + _ "github.com/cosmos/gogoproto/gogoproto" + grpc1 "github.com/cosmos/gogoproto/grpc" + proto "github.com/cosmos/gogoproto/proto" + _ "google.golang.org/genproto/googleapis/api/annotations" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// =============================== Params +type QueryParamsRequest struct { +} + +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 *QueryParamsRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryParamsRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryParamsRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryParamsRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryParamsRequest.Merge(m, src) +} +func (m *QueryParamsRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryParamsRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryParamsRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryParamsRequest proto.InternalMessageInfo + +type QueryParamsResponse struct { + Params Params `protobuf:"bytes,1,opt,name=params,proto3" json:"params"` +} + +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 *QueryParamsResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryParamsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryParamsResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryParamsResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryParamsResponse.Merge(m, src) +} +func (m *QueryParamsResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryParamsResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryParamsResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryParamsResponse proto.InternalMessageInfo + +func (m *QueryParamsResponse) GetParams() Params { + if m != nil { + return m.Params + } + return Params{} +} + +func init() { + 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{ + // 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. +var _ context.Context +var _ grpc.ClientConn + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion4 + +// QueryClient is the client API for Query service. +// +// 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 *QueryParamsRequest, opts ...grpc.CallOption) (*QueryParamsResponse, error) +} + +type queryClient struct { + cc grpc1.ClientConn +} + +func NewQueryClient(cc grpc1.ClientConn) QueryClient { + return &queryClient{cc} +} + +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 + } + return out, nil +} + +// QueryServer is the server API for Query service. +type QueryServer interface { + 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 *QueryParamsRequest) (*QueryParamsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Params not implemented") +} + +func RegisterQueryServer(s grpc1.Server, srv QueryServer) { + s.RegisterService(&_Query_serviceDesc, srv) +} + +func _Query_Params_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryParamsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).Params(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/terra.tax2gas.v1beta1.Query/Params", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).Params(ctx, req.(*QueryParamsRequest)) + } + return interceptor(ctx, in, info, handler) +} + +var _Query_serviceDesc = grpc.ServiceDesc{ + ServiceName: "terra.tax2gas.v1beta1.Query", + HandlerType: (*QueryServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "Params", + Handler: _Query_Params_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "terra/tax2gas/v1beta1/query.proto", +} + +func (m *QueryParamsRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryParamsRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryParamsRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *QueryParamsResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryParamsResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryParamsResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.Params.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func encodeVarintQuery(dAtA []byte, offset int, v uint64) int { + offset -= sovQuery(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *QueryParamsRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *QueryParamsResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.Params.Size() + n += 1 + l + sovQuery(uint64(l)) + return n +} + +func sovQuery(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozQuery(x uint64) (n int) { + return sovQuery(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *QueryParamsRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryParamsRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryParamsRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryParamsResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryParamsResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryParamsResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Params", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Params.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipQuery(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowQuery + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowQuery + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowQuery + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthQuery + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupQuery + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthQuery + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthQuery = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowQuery = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupQuery = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/tax2gas/types/query.pb.gw.go b/x/tax2gas/types/query.pb.gw.go new file mode 100644 index 000000000..27f6ee6cf --- /dev/null +++ b/x/tax2gas/types/query.pb.gw.go @@ -0,0 +1,153 @@ +// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT. +// source: terra/tax2gas/v1beta1/query.proto + +/* +Package types is a reverse proxy. + +It translates gRPC into RESTful JSON APIs. +*/ +package types + +import ( + "context" + "io" + "net/http" + + "github.com/golang/protobuf/descriptor" + "github.com/golang/protobuf/proto" + "github.com/grpc-ecosystem/grpc-gateway/runtime" + "github.com/grpc-ecosystem/grpc-gateway/utilities" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/grpclog" + "google.golang.org/grpc/metadata" + "google.golang.org/grpc/status" +) + +// Suppress "imported and not used" errors +var _ codes.Code +var _ io.Reader +var _ status.Status +var _ = runtime.String +var _ = utilities.NewDoubleArray +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 QueryParamsRequest + var metadata runtime.ServerMetadata + + msg, err := client.Params(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +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 QueryParamsRequest + var metadata runtime.ServerMetadata + + msg, err := server.Params(ctx, &protoReq) + return msg, metadata, err + +} + +// RegisterQueryHandlerServer registers the http handlers for service Query to "mux". +// UnaryRPC :call QueryServer directly. +// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. +// Note that using this registration option will cause many gRPC library features to stop working. Consider using RegisterQueryHandlerFromEndpoint instead. +func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, server QueryServer) error { + + mux.Handle("GET", pattern_Query_Params_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_Params_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_Params_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + return nil +} + +// RegisterQueryHandlerFromEndpoint is same as RegisterQueryHandler but +// automatically dials to "endpoint" and closes the connection when "ctx" gets done. +func RegisterQueryHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) { + conn, err := grpc.Dial(endpoint, opts...) + if err != nil { + return err + } + defer func() { + if err != nil { + if cerr := conn.Close(); cerr != nil { + grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) + } + return + } + go func() { + <-ctx.Done() + if cerr := conn.Close(); cerr != nil { + grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) + } + }() + }() + + return RegisterQueryHandler(ctx, mux, conn) +} + +// RegisterQueryHandler registers the http handlers for service Query to "mux". +// The handlers forward requests to the grpc endpoint over "conn". +func RegisterQueryHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error { + return RegisterQueryHandlerClient(ctx, mux, NewQueryClient(conn)) +} + +// RegisterQueryHandlerClient registers the http handlers for service Query +// to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "QueryClient". +// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "QueryClient" +// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in +// "QueryClient" to call the correct interceptors. +func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, client QueryClient) error { + + mux.Handle("GET", pattern_Query_Params_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Query_Params_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_Params_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + return nil +} + +var ( + pattern_Query_Params_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"terra", "tax2gas", "Params"}, "", runtime.AssumeColonVerbOpt(false))) +) + +var ( + forward_Query_Params_0 = runtime.ForwardResponseMessage +) diff --git a/x/tax2gas/types/tx.pb.go b/x/tax2gas/types/tx.pb.go new file mode 100644 index 000000000..14e51e963 --- /dev/null +++ b/x/tax2gas/types/tx.pb.go @@ -0,0 +1,599 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: terra/tax2gas/v1beta1/tx.proto + +package types + +import ( + context "context" + fmt "fmt" + _ "github.com/cosmos/cosmos-proto" + _ "github.com/cosmos/cosmos-sdk/types/msgservice" + _ "github.com/cosmos/cosmos-sdk/types/tx/amino" + _ "github.com/cosmos/gogoproto/gogoproto" + grpc1 "github.com/cosmos/gogoproto/grpc" + proto "github.com/cosmos/gogoproto/proto" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// MsgUpdateParams is the Msg/UpdateParams request type. +// +// Since: cosmos-sdk 0.47 +type MsgUpdateParams struct { + // authority is the address that controls the module (defaults to x/gov unless overwritten). + Authority string `protobuf:"bytes,1,opt,name=authority,proto3" json:"authority,omitempty"` + // params defines the x/tax2gas parameters to update. + // + // NOTE: All parameters must be supplied. + Params Params `protobuf:"bytes,2,opt,name=params,proto3" json:"params"` +} + +func (m *MsgUpdateParams) Reset() { *m = MsgUpdateParams{} } +func (m *MsgUpdateParams) String() string { return proto.CompactTextString(m) } +func (*MsgUpdateParams) ProtoMessage() {} +func (*MsgUpdateParams) Descriptor() ([]byte, []int) { + return fileDescriptor_a20cba19b3d258de, []int{0} +} +func (m *MsgUpdateParams) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgUpdateParams) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgUpdateParams.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgUpdateParams) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgUpdateParams.Merge(m, src) +} +func (m *MsgUpdateParams) XXX_Size() int { + return m.Size() +} +func (m *MsgUpdateParams) XXX_DiscardUnknown() { + xxx_messageInfo_MsgUpdateParams.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgUpdateParams proto.InternalMessageInfo + +func (m *MsgUpdateParams) GetAuthority() string { + if m != nil { + return m.Authority + } + return "" +} + +func (m *MsgUpdateParams) GetParams() Params { + if m != nil { + return m.Params + } + return Params{} +} + +// MsgUpdateParamsResponse defines the response structure for executing a +// MsgUpdateParams message. +// +// Since: cosmos-sdk 0.47 +type MsgUpdateParamsResponse struct { +} + +func (m *MsgUpdateParamsResponse) Reset() { *m = MsgUpdateParamsResponse{} } +func (m *MsgUpdateParamsResponse) String() string { return proto.CompactTextString(m) } +func (*MsgUpdateParamsResponse) ProtoMessage() {} +func (*MsgUpdateParamsResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_a20cba19b3d258de, []int{1} +} +func (m *MsgUpdateParamsResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgUpdateParamsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgUpdateParamsResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgUpdateParamsResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgUpdateParamsResponse.Merge(m, src) +} +func (m *MsgUpdateParamsResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgUpdateParamsResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgUpdateParamsResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgUpdateParamsResponse proto.InternalMessageInfo + +func init() { + proto.RegisterType((*MsgUpdateParams)(nil), "terra.tax2gas.v1beta1.MsgUpdateParams") + proto.RegisterType((*MsgUpdateParamsResponse)(nil), "terra.tax2gas.v1beta1.MsgUpdateParamsResponse") +} + +func init() { proto.RegisterFile("terra/tax2gas/v1beta1/tx.proto", fileDescriptor_a20cba19b3d258de) } + +var fileDescriptor_a20cba19b3d258de = []byte{ + // 365 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0x2b, 0x49, 0x2d, 0x2a, + 0x4a, 0xd4, 0x2f, 0x49, 0xac, 0x30, 0x4a, 0x4f, 0x2c, 0xd6, 0x2f, 0x33, 0x4c, 0x4a, 0x2d, 0x49, + 0x34, 0xd4, 0x2f, 0xa9, 0xd0, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x12, 0x05, 0xcb, 0xeb, 0x41, + 0xe5, 0xf5, 0xa0, 0xf2, 0x52, 0x22, 0xe9, 0xf9, 0xe9, 0xf9, 0x60, 0x15, 0xfa, 0x20, 0x16, 0x44, + 0xb1, 0x94, 0x78, 0x72, 0x7e, 0x71, 0x6e, 0x7e, 0xb1, 0x7e, 0x6e, 0x71, 0xba, 0x7e, 0x99, 0x21, + 0x88, 0x82, 0x4a, 0x08, 0x26, 0xe6, 0x66, 0xe6, 0xe5, 0xeb, 0x83, 0x49, 0xa8, 0x90, 0x24, 0x44, + 0x6d, 0x3c, 0xc4, 0x10, 0x08, 0x07, 0x2a, 0xa5, 0x8c, 0xdd, 0x4d, 0xe9, 0xa9, 0x79, 0xa9, 0xc5, + 0x99, 0x50, 0x45, 0x4a, 0xfb, 0x19, 0xb9, 0xf8, 0x7d, 0x8b, 0xd3, 0x43, 0x0b, 0x52, 0x12, 0x4b, + 0x52, 0x03, 0x12, 0x8b, 0x12, 0x73, 0x8b, 0x85, 0xcc, 0xb8, 0x38, 0x13, 0x4b, 0x4b, 0x32, 0xf2, + 0x8b, 0x32, 0x4b, 0x2a, 0x25, 0x18, 0x15, 0x18, 0x35, 0x38, 0x9d, 0x24, 0x2e, 0x6d, 0xd1, 0x15, + 0x81, 0x9a, 0xee, 0x98, 0x92, 0x52, 0x94, 0x5a, 0x5c, 0x1c, 0x5c, 0x52, 0x94, 0x99, 0x97, 0x1e, + 0x84, 0x50, 0x2a, 0xe4, 0xc0, 0xc5, 0x56, 0x00, 0x36, 0x41, 0x82, 0x49, 0x81, 0x51, 0x83, 0xdb, + 0x48, 0x56, 0x0f, 0xab, 0xaf, 0xf5, 0x20, 0xd6, 0x38, 0x71, 0x9e, 0xb8, 0x27, 0xcf, 0xb0, 0xe2, + 0xf9, 0x06, 0x2d, 0xc6, 0x20, 0xa8, 0x3e, 0x2b, 0xa3, 0xa6, 0xe7, 0x1b, 0xb4, 0x10, 0x26, 0x76, + 0x3d, 0xdf, 0xa0, 0x25, 0x0f, 0xf1, 0x45, 0x05, 0xdc, 0x1f, 0x68, 0xae, 0x55, 0x92, 0xe4, 0x12, + 0x47, 0x13, 0x0a, 0x4a, 0x2d, 0x2e, 0xc8, 0xcf, 0x2b, 0x4e, 0x35, 0x2a, 0xe1, 0x62, 0xf6, 0x2d, + 0x4e, 0x17, 0x4a, 0xe3, 0xe2, 0x41, 0xf1, 0x9f, 0x1a, 0x0e, 0x77, 0xa1, 0x19, 0x23, 0xa5, 0x47, + 0x9c, 0x3a, 0x98, 0x75, 0x52, 0xac, 0x0d, 0x20, 0xcf, 0x38, 0x79, 0x9d, 0x78, 0x24, 0xc7, 0x78, + 0xe1, 0x91, 0x1c, 0xe3, 0x83, 0x47, 0x72, 0x8c, 0x13, 0x1e, 0xcb, 0x31, 0x5c, 0x78, 0x2c, 0xc7, + 0x70, 0xe3, 0xb1, 0x1c, 0x43, 0x94, 0x41, 0x7a, 0x66, 0x49, 0x46, 0x69, 0x92, 0x5e, 0x72, 0x7e, + 0xae, 0x7e, 0x72, 0x4e, 0x62, 0x71, 0x71, 0x66, 0xb2, 0x2e, 0xc4, 0x7b, 0xc9, 0xf9, 0x45, 0xa9, + 0xfa, 0x65, 0xc6, 0x48, 0xde, 0x2c, 0xa9, 0x2c, 0x48, 0x2d, 0x4e, 0x62, 0x03, 0xc7, 0x92, 0x31, + 0x20, 0x00, 0x00, 0xff, 0xff, 0xd2, 0x9a, 0x8b, 0x48, 0x60, 0x02, 0x00, 0x00, +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion4 + +// MsgClient is the client API for Msg service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type MsgClient interface { + UpdateParams(ctx context.Context, in *MsgUpdateParams, opts ...grpc.CallOption) (*MsgUpdateParamsResponse, error) +} + +type msgClient struct { + cc grpc1.ClientConn +} + +func NewMsgClient(cc grpc1.ClientConn) MsgClient { + return &msgClient{cc} +} + +func (c *msgClient) UpdateParams(ctx context.Context, in *MsgUpdateParams, opts ...grpc.CallOption) (*MsgUpdateParamsResponse, error) { + out := new(MsgUpdateParamsResponse) + err := c.cc.Invoke(ctx, "/terra.tax2gas.v1beta1.Msg/UpdateParams", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// MsgServer is the server API for Msg service. +type MsgServer interface { + UpdateParams(context.Context, *MsgUpdateParams) (*MsgUpdateParamsResponse, error) +} + +// UnimplementedMsgServer can be embedded to have forward compatible implementations. +type UnimplementedMsgServer struct { +} + +func (*UnimplementedMsgServer) UpdateParams(ctx context.Context, req *MsgUpdateParams) (*MsgUpdateParamsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method UpdateParams not implemented") +} + +func RegisterMsgServer(s grpc1.Server, srv MsgServer) { + s.RegisterService(&_Msg_serviceDesc, srv) +} + +func _Msg_UpdateParams_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgUpdateParams) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).UpdateParams(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/terra.tax2gas.v1beta1.Msg/UpdateParams", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).UpdateParams(ctx, req.(*MsgUpdateParams)) + } + return interceptor(ctx, in, info, handler) +} + +var _Msg_serviceDesc = grpc.ServiceDesc{ + ServiceName: "terra.tax2gas.v1beta1.Msg", + HandlerType: (*MsgServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "UpdateParams", + Handler: _Msg_UpdateParams_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "terra/tax2gas/v1beta1/tx.proto", +} + +func (m *MsgUpdateParams) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgUpdateParams) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgUpdateParams) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.Params.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + if len(m.Authority) > 0 { + i -= len(m.Authority) + copy(dAtA[i:], m.Authority) + i = encodeVarintTx(dAtA, i, uint64(len(m.Authority))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgUpdateParamsResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgUpdateParamsResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgUpdateParamsResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func encodeVarintTx(dAtA []byte, offset int, v uint64) int { + offset -= sovTx(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *MsgUpdateParams) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Authority) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = m.Params.Size() + n += 1 + l + sovTx(uint64(l)) + return n +} + +func (m *MsgUpdateParamsResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func sovTx(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozTx(x uint64) (n int) { + return sovTx(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *MsgUpdateParams) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgUpdateParams: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgUpdateParams: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Authority", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Authority = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Params", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Params.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgUpdateParamsResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgUpdateParamsResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgUpdateParamsResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipTx(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTx + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTx + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTx + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthTx + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupTx + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthTx + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthTx = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowTx = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupTx = fmt.Errorf("proto: unexpected end of group") +) diff --git a/custom/auth/ante/fee_tax.go b/x/tax2gas/utils/fee_tax.go similarity index 62% rename from custom/auth/ante/fee_tax.go rename to x/tax2gas/utils/fee_tax.go index 96a0e48d6..fd00be723 100644 --- a/custom/auth/ante/fee_tax.go +++ b/x/tax2gas/utils/fee_tax.go @@ -1,16 +1,19 @@ -package ante +package utils import ( "regexp" "strings" + errorsmod "cosmossdk.io/errors" + sdkmath "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" + "github.com/classic-terra/core/v3/x/tax2gas/types" ) var IBCRegexp = regexp.MustCompile("^ibc/[a-fA-F0-9]{64}$") @@ -20,7 +23,7 @@ func isIBCDenom(denom string) bool { } // FilterMsgAndComputeTax computes the stability tax on messages. -func FilterMsgAndComputeTax(ctx sdk.Context, tk TreasuryKeeper, msgs ...sdk.Msg) sdk.Coins { +func FilterMsgAndComputeTax(ctx sdk.Context, tk types.TreasuryKeeper, msgs ...sdk.Msg) sdk.Coins { taxes := sdk.Coins{} for _, msg := range msgs { @@ -77,7 +80,7 @@ func FilterMsgAndComputeTax(ctx sdk.Context, tk TreasuryKeeper, msgs ...sdk.Msg) } // computes the stability tax according to tax-rate and tax-cap -func computeTax(ctx sdk.Context, tk TreasuryKeeper, principal sdk.Coins) sdk.Coins { +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{} @@ -112,17 +115,45 @@ func computeTax(ctx sdk.Context, tk TreasuryKeeper, principal sdk.Coins) sdk.Coi return taxes } -func isOracleTx(msgs []sdk.Msg) bool { - for _, msg := range msgs { - switch msg.(type) { - case *oracleexported.MsgAggregateExchangeRatePrevote: - continue - case *oracleexported.MsgAggregateExchangeRateVote: - continue +func ComputeGas(gasPrices sdk.DecCoins, taxes sdk.Coins) (uint64, error) { + taxes = taxes.Sort() + tax2gas := sdkmath.ZeroInt() + // Convert to gas + i, j := 0, 0 + for i < len(gasPrices) && j < len(taxes) { + switch { + case gasPrices[i].Denom == taxes[j].Denom: + tax2gas = tax2gas.Add(sdk.NewDec(taxes[j].Amount.Int64()).Quo((gasPrices[i].Amount)).Ceil().RoundInt()) + i++ + j++ + case gasPrices[i].Denom < taxes[j].Denom: + i++ default: - return false + j++ + } + } + + return tax2gas.Uint64(), nil +} + +func ComputeFeesOnGasConsumed(tx sdk.Tx, gasPrices sdk.DecCoins, gas uint64) (sdk.Coins, error) { + feeTx, ok := tx.(sdk.FeeTx) + if !ok { + return nil, errorsmod.Wrap(sdkerrors.ErrTxDecode, "Tx must be a FeeTx") + } + + isOracleTx := IsOracleTx(feeTx.GetMsgs()) + + 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()) } } - return true + return gasFees, nil } diff --git a/x/tax2gas/utils/utils.go b/x/tax2gas/utils/utils.go new file mode 100644 index 000000000..c585384ea --- /dev/null +++ b/x/tax2gas/utils/utils.go @@ -0,0 +1,125 @@ +package utils + +import ( + "math" + + sdk "github.com/cosmos/cosmos-sdk/types" + + oracleexported "github.com/classic-terra/core/v3/x/oracle/exported" +) + +// GetTxPriority returns a naive tx priority based on the amount of the smallest denomination of the gas price +// provided in a transaction. +// NOTE: This implementation should be used with a great consideration as it opens potential attack vectors +// where txs with multiple coins could not be prioritize as expected. +func GetTxPriority(fee sdk.Coins, gas int64) int64 { + var priority int64 + for _, c := range fee { + p := int64(math.MaxInt64) + gasPrice := c.Amount.QuoRaw(gas) + if gasPrice.IsInt64() { + p = gasPrice.Int64() + } + if priority == 0 || p < priority { + priority = p + } + } + + return priority +} + +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 +} + +// Find returns true and Dec amount if the denom exists in gasPrices. Otherwise it returns false +// and a zero dec. Uses binary search. +// CONTRACT: gasPrices must be valid (sorted). +func GetGasPriceByDenom(gasPrices sdk.DecCoins, denom string) (bool, sdk.Dec) { + switch len(gasPrices) { + case 0: + return false, sdk.ZeroDec() + + case 1: + gasPrice := gasPrices[0] + if gasPrice.Denom == denom { + return true, gasPrice.Amount + } + return false, sdk.ZeroDec() + + default: + midIdx := len(gasPrices) / 2 // 2:1, 3:1, 4:2 + gasPrice := gasPrices[midIdx] + switch { + case denom < gasPrice.Denom: + return GetGasPriceByDenom(gasPrices[:midIdx], denom) + case denom == gasPrice.Denom: + return true, gasPrice.Amount + default: + return GetGasPriceByDenom(gasPrices[midIdx+1:], denom) + } + } +} + +func CalculateTaxesAndPayableFee(gasPrices sdk.DecCoins, feeCoins sdk.Coins, taxGas uint64, totalGasRemaining uint64) (taxes sdk.Coins, payableFees sdk.Coins, gasRemaining uint64) { + taxGasRemaining := taxGas + taxes = sdk.NewCoins() + payableFees = sdk.NewCoins() + gasRemaining = totalGasRemaining + for _, feeCoin := range feeCoins { + found, gasPrice := GetGasPriceByDenom(gasPrices, feeCoin.Denom) + if !found { + continue + } + taxFeeRequired := sdk.NewCoin(feeCoin.Denom, gasPrice.MulInt64(int64(taxGasRemaining)).Ceil().RoundInt()) + totalFeeRequired := sdk.NewCoin(feeCoin.Denom, gasPrice.MulInt64(int64(gasRemaining)).Ceil().RoundInt()) + + switch { + case taxGasRemaining > 0: + switch { + case feeCoin.IsGTE(totalFeeRequired): + taxes = taxes.Add(taxFeeRequired) + payableFees = payableFees.Add(totalFeeRequired) + taxGasRemaining = 0 + gasRemaining = 0 + return + case feeCoin.IsGTE(taxFeeRequired): + taxes = taxes.Add(taxFeeRequired) + taxGasRemaining = 0 + payableFees = payableFees.Add(feeCoin) + totalFeeRemaining := sdk.NewDecCoinFromCoin(totalFeeRequired.Sub(feeCoin)) + gasRemaining = uint64(totalFeeRemaining.Amount.Quo(gasPrice).Ceil().RoundInt64()) + default: + taxes = taxes.Add(feeCoin) + payableFees = payableFees.Add(feeCoin) + taxFeeRemaining := sdk.NewDecCoinFromCoin(taxFeeRequired.Sub(feeCoin)) + taxGasRemaining = uint64(taxFeeRemaining.Amount.Quo(gasPrice).Ceil().RoundInt64()) + gasRemaining = gasRemaining - (taxGas - taxGasRemaining) + } + case gasRemaining > 0: + if feeCoin.IsGTE(totalFeeRequired) { + payableFees = payableFees.Add(totalFeeRequired) + gasRemaining = 0 + return + } else { + payableFees = payableFees.Add(feeCoin) + totalFeeRemaining := sdk.NewDecCoinFromCoin(totalFeeRequired.Sub(feeCoin)) + gasRemaining = uint64(totalFeeRemaining.Amount.Quo(gasPrice).Ceil().RoundInt64()) + } + default: + return + } + } + return +} diff --git a/x/treasury/keeper/params.go b/x/treasury/keeper/params.go index c9e101c0b..8c6e84197 100644 --- a/x/treasury/keeper/params.go +++ b/x/treasury/keeper/params.go @@ -66,6 +66,15 @@ func (k Keeper) SetMinInitialDepositRatio(ctx sdk.Context, minInitialDepositRati k.paramSpace.Set(ctx, types.KeyMinInitialDepositRatio, minInitialDepositRatio) } +func (k Keeper) GetOracleSplitRate(ctx sdk.Context) (res sdk.Dec) { + k.paramSpace.Get(ctx, types.KeyOracleSplit, &res) + return +} + +func (k Keeper) SetOracleSplitRate(ctx sdk.Context, oracleSplit sdk.Dec) { + k.paramSpace.Set(ctx, types.KeyOracleSplit, oracleSplit) +} + // GetParams returns the total set of treasury parameters. func (k Keeper) GetParams(ctx sdk.Context) (params types.Params) { k.paramSpace.GetParamSetIfExists(ctx, ¶ms) diff --git a/x/treasury/types/params.go b/x/treasury/types/params.go index 45eb7e8e1..fb739730a 100644 --- a/x/treasury/types/params.go +++ b/x/treasury/types/params.go @@ -22,6 +22,7 @@ var ( KeyWindowProbation = []byte("WindowProbation") KeyBurnTaxSplit = []byte("BurnTaxSplit") KeyMinInitialDepositRatio = []byte("MinInitialDepositRatio") + KeyOracleSplit = []byte("OracleSplit") ) // Default parameter values @@ -47,6 +48,7 @@ var ( DefaultRewardWeight = sdk.NewDecWithPrec(5, 2) // 5% DefaultBurnTaxSplit = sdk.NewDecWithPrec(1, 1) // 10% goes to community pool, 90% burn DefaultMinInitialDepositRatio = sdk.ZeroDec() // 0% min initial deposit + DefaultOracleSplit = sdk.OneDec() // 100% oracle, community tax (CP) is deducted before oracle split ) var _ paramstypes.ParamSet = &Params{} @@ -63,6 +65,7 @@ func DefaultParams() Params { WindowProbation: DefaultWindowProbation, BurnTaxSplit: DefaultBurnTaxSplit, MinInitialDepositRatio: DefaultMinInitialDepositRatio, + OracleSplit: DefaultOracleSplit, } } @@ -90,6 +93,7 @@ func (p *Params) ParamSetPairs() paramstypes.ParamSetPairs { paramstypes.NewParamSetPair(KeyWindowProbation, &p.WindowProbation, validateWindowProbation), paramstypes.NewParamSetPair(KeyBurnTaxSplit, &p.BurnTaxSplit, validateBurnTaxSplit), paramstypes.NewParamSetPair(KeyMinInitialDepositRatio, &p.MinInitialDepositRatio, validateMinInitialDepositRatio), + paramstypes.NewParamSetPair(KeyOracleSplit, &p.OracleSplit, validateOraceSplit), } } @@ -137,6 +141,14 @@ func (p Params) Validate() error { return fmt.Errorf("treasury parameter WindowLong must be bigger than WindowShort: (%d, %d)", p.WindowLong, p.WindowShort) } + if p.OracleSplit.IsNegative() { + return fmt.Errorf("treasury parameter OracleSplit must be positive: %s", p.OracleSplit) + } + + if p.OracleSplit.GT(sdk.OneDec()) { + return fmt.Errorf("treasury parameter OracleSplit must be less than or equal to 1.0: %s", p.OracleSplit) + } + return nil } @@ -268,3 +280,20 @@ func validateMinInitialDepositRatio(i interface{}) error { return nil } + +func validateOraceSplit(i interface{}) error { + v, ok := i.(sdk.Dec) + if !ok { + return fmt.Errorf("invalid paramater type: %T", i) + } + + if v.IsNegative() { + return fmt.Errorf("oracle split must be positive: %s", v) + } + + if v.GT(sdk.OneDec()) { + return fmt.Errorf("oracle split must be less than or equal to 1.0: %s", v) + } + + return nil +} diff --git a/x/treasury/types/treasury.pb.go b/x/treasury/types/treasury.pb.go index b6e05e793..bcd8f5061 100644 --- a/x/treasury/types/treasury.pb.go +++ b/x/treasury/types/treasury.pb.go @@ -37,6 +37,7 @@ type Params struct { WindowProbation uint64 `protobuf:"varint,7,opt,name=window_probation,json=windowProbation,proto3" json:"window_probation,omitempty" yaml:"window_probation"` BurnTaxSplit github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,8,opt,name=burn_tax_split,json=burnTaxSplit,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"burn_tax_split" yaml:"burn_tax_split"` MinInitialDepositRatio github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,9,opt,name=min_initial_deposit_ratio,json=minInitialDepositRatio,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"min_initial_deposit_ratio" yaml:"min_initial_deposit_ratio"` + OracleSplit github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,10,opt,name=oracle_split,json=oracleSplit,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"oracle_split" yaml:"oracle_split"` } func (m *Params) Reset() { *m = Params{} } @@ -257,58 +258,59 @@ func init() { } var fileDescriptor_353bb3a9c554268e = []byte{ - // 804 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x55, 0xbf, 0x6f, 0x23, 0x45, - 0x14, 0xf6, 0xe2, 0x23, 0xb1, 0xc7, 0x3e, 0x9c, 0x9b, 0x0b, 0xce, 0xfa, 0x40, 0x5e, 0x6b, 0x25, - 0x90, 0x29, 0x62, 0x2b, 0x77, 0x05, 0x52, 0x1a, 0x24, 0x27, 0x80, 0x22, 0x40, 0x58, 0x7b, 0x01, - 0x24, 0x9a, 0x65, 0x3c, 0x1e, 0xad, 0x07, 0xbc, 0x33, 0xab, 0x99, 0xf1, 0x65, 0x0d, 0x12, 0x05, - 0x12, 0x3d, 0xa2, 0x42, 0x40, 0x71, 0x35, 0x35, 0xe2, 0x6f, 0x48, 0x19, 0x51, 0x21, 0x0a, 0x03, - 0x49, 0x43, 0xed, 0xbf, 0x00, 0xed, 0xcc, 0xf8, 0x27, 0x09, 0x9c, 0x95, 0xca, 0x7e, 0xef, 0x7d, - 0xef, 0xfb, 0xbe, 0x79, 0xbb, 0x6f, 0x16, 0xbc, 0xa2, 0x88, 0x10, 0xa8, 0xad, 0x04, 0x41, 0x72, - 0x24, 0xc6, 0xed, 0x27, 0x07, 0x3d, 0xa2, 0xd0, 0xc1, 0x3c, 0xd1, 0x4a, 0x04, 0x57, 0x1c, 0x56, - 0x35, 0xac, 0x35, 0xcf, 0x5a, 0xd8, 0x83, 0x3a, 0xe6, 0x32, 0xe6, 0xb2, 0xdd, 0x43, 0x92, 0xcc, - 0x7b, 0x31, 0xa7, 0xcc, 0xf4, 0x3d, 0xa8, 0x99, 0x7a, 0xa8, 0xa3, 0xb6, 0x09, 0x6c, 0x69, 0x37, - 0xe2, 0x11, 0x37, 0xf9, 0xec, 0x9f, 0xc9, 0xfa, 0x7f, 0x6d, 0x83, 0xad, 0x2e, 0x12, 0x28, 0x96, - 0x10, 0x03, 0xa0, 0x50, 0x1a, 0x26, 0x7c, 0x48, 0xf1, 0xd8, 0x75, 0x1a, 0x4e, 0xb3, 0xf4, 0xf0, - 0xb5, 0xd6, 0xf5, 0x46, 0x5a, 0x5d, 0x8d, 0x3a, 0xe2, 0x4c, 0x2a, 0x81, 0x28, 0x53, 0xb2, 0x53, - 0x3b, 0x9f, 0x78, 0xb9, 0xe9, 0xc4, 0xbb, 0x37, 0x46, 0xf1, 0xf0, 0xd0, 0x5f, 0x50, 0xf9, 0x41, - 0x51, 0xa1, 0xd4, 0x34, 0xc0, 0x21, 0xb8, 0x2b, 0xc8, 0x19, 0x12, 0xfd, 0x99, 0xce, 0x73, 0x9b, - 0xea, 0xbc, 0x6c, 0x75, 0x76, 0x8d, 0xce, 0x0a, 0x9b, 0x1f, 0x94, 0x4d, 0x6c, 0xd5, 0x7e, 0x74, - 0x40, 0x4d, 0x12, 0x1a, 0x31, 0xca, 0x05, 0x8a, 0x48, 0xd8, 0x1b, 0x89, 0x3e, 0x61, 0xa1, 0x42, - 0x22, 0x22, 0xca, 0xcd, 0x37, 0x9c, 0x66, 0xb1, 0xf3, 0x49, 0xc6, 0xf7, 0xfb, 0xc4, 0x7b, 0x35, - 0xa2, 0x6a, 0x30, 0xea, 0xb5, 0x30, 0x8f, 0xed, 0xe0, 0xec, 0xcf, 0xbe, 0xec, 0x7f, 0xd6, 0x56, - 0xe3, 0x84, 0xc8, 0xd6, 0x31, 0xc1, 0xd3, 0x89, 0xd7, 0x30, 0xca, 0x37, 0x12, 0xfb, 0xbf, 0xfe, - 0xbc, 0x0f, 0xec, 0xec, 0x8f, 0x09, 0x0e, 0xf6, 0x96, 0x90, 0x1d, 0x0d, 0x3c, 0xd5, 0x38, 0xf8, - 0x95, 0x03, 0x76, 0x62, 0xca, 0x28, 0x8b, 0x42, 0xca, 0xb0, 0x20, 0x31, 0x61, 0xca, 0xbd, 0xa3, - 0x5d, 0x7d, 0xb4, 0xb1, 0xab, 0x3d, 0xe3, 0x6a, 0x9d, 0x6f, 0xdd, 0x4c, 0xc5, 0x00, 0x4e, 0x66, - 0x75, 0x78, 0x08, 0xca, 0x67, 0x94, 0xf5, 0xf9, 0x59, 0x28, 0x07, 0x5c, 0x28, 0xf7, 0xf9, 0x86, - 0xd3, 0xbc, 0xd3, 0xd9, 0x9b, 0x4e, 0xbc, 0xfb, 0x86, 0x71, 0xb9, 0xea, 0x07, 0x25, 0x13, 0x3e, - 0xce, 0x22, 0xf8, 0x3a, 0xb0, 0x61, 0x38, 0xe4, 0x2c, 0x72, 0xb7, 0x74, 0x6b, 0x75, 0x3a, 0xf1, - 0xe0, 0x4a, 0x6b, 0x56, 0xf4, 0x03, 0x60, 0xa2, 0x77, 0x39, 0x8b, 0xe0, 0x5b, 0x60, 0xc7, 0xd6, - 0x12, 0xc1, 0x7b, 0x48, 0x51, 0xce, 0xdc, 0x6d, 0xdd, 0xfd, 0xd2, 0xe2, 0x28, 0xeb, 0x08, 0x3f, - 0xa8, 0x98, 0x54, 0x77, 0x96, 0x81, 0x5f, 0x80, 0x17, 0x7a, 0x23, 0x91, 0x0d, 0x3e, 0x0d, 0x65, - 0x32, 0xa4, 0xca, 0x2d, 0xe8, 0xf1, 0x7d, 0xb0, 0xf1, 0xf8, 0x5e, 0x34, 0x9a, 0xab, 0x6c, 0xeb, - 0xc3, 0x2b, 0x67, 0xe5, 0x53, 0x94, 0x3e, 0xce, 0x8a, 0xf0, 0x07, 0x07, 0xd4, 0x62, 0xca, 0x42, - 0xca, 0xa8, 0xa2, 0x68, 0x18, 0xf6, 0x49, 0xc2, 0x25, 0x55, 0xa1, 0xc8, 0xbc, 0xb9, 0xc5, 0xdb, - 0xbd, 0x5d, 0x37, 0x12, 0xaf, 0x7b, 0xaa, 0xc6, 0x94, 0x9d, 0x18, 0xe0, 0xb1, 0xc1, 0x05, 0x19, - 0xec, 0xb0, 0xf0, 0xdd, 0x53, 0x2f, 0xf7, 0xf7, 0x53, 0xcf, 0xf1, 0x7f, 0xc9, 0x83, 0x7b, 0xff, - 0xda, 0x23, 0xf8, 0x29, 0x28, 0x08, 0xa4, 0x48, 0x18, 0x53, 0xa6, 0x97, 0xbd, 0xd8, 0x79, 0x7f, - 0x63, 0xaf, 0x15, 0xbb, 0x83, 0x96, 0x67, 0xdd, 0xda, 0x76, 0x56, 0x78, 0x8f, 0xb2, 0x85, 0x16, - 0x4a, 0xf5, 0xc2, 0xdf, 0x5a, 0x0b, 0xa5, 0xd7, 0x6b, 0xa1, 0x14, 0xbe, 0x01, 0xf2, 0x18, 0x25, - 0x7a, 0xb9, 0x4b, 0x0f, 0x6b, 0x2d, 0x0b, 0xc9, 0x2e, 0xcc, 0xf9, 0xa5, 0x72, 0xc4, 0x29, 0xeb, - 0x40, 0x7b, 0x8f, 0x00, 0xc3, 0x8b, 0x51, 0xe2, 0x07, 0x59, 0x27, 0xfc, 0x12, 0x54, 0xf0, 0x00, - 0xb1, 0x88, 0x84, 0x73, 0xcf, 0x66, 0x27, 0x3f, 0xdc, 0xd8, 0x73, 0xd5, 0x72, 0xaf, 0xd2, 0xad, - 0x5b, 0xbf, 0x6b, 0xea, 0x81, 0x39, 0xc0, 0xd2, 0x83, 0xfb, 0xde, 0x01, 0x3b, 0x6f, 0x26, 0x1c, - 0x0f, 0x4e, 0x51, 0xda, 0x15, 0x1c, 0x13, 0xd2, 0x97, 0xf0, 0x6b, 0x07, 0x94, 0xf5, 0xe5, 0x6a, - 0x13, 0xae, 0xd3, 0xc8, 0xff, 0xf7, 0x49, 0xdf, 0xb6, 0x27, 0xbd, 0xbf, 0x74, 0x33, 0xdb, 0x66, - 0xff, 0xa7, 0x3f, 0xbc, 0xe6, 0x33, 0x1c, 0x27, 0xe3, 0x91, 0x41, 0x49, 0x2d, 0x7c, 0xf8, 0xdf, - 0x3a, 0x60, 0x57, 0x9b, 0xb3, 0x2f, 0xdf, 0x89, 0x94, 0x23, 0xc4, 0x30, 0x81, 0x9f, 0x83, 0x02, - 0xb5, 0xff, 0xff, 0xdf, 0xdb, 0x91, 0xf5, 0x66, 0x9f, 0xee, 0xac, 0x71, 0x33, 0x5f, 0x73, 0xbd, - 0xce, 0x3b, 0xe7, 0x97, 0x75, 0xe7, 0xe2, 0xb2, 0xee, 0xfc, 0x79, 0x59, 0x77, 0xbe, 0xb9, 0xaa, - 0xe7, 0x2e, 0xae, 0xea, 0xb9, 0xdf, 0xae, 0xea, 0xb9, 0x8f, 0x0f, 0x96, 0xd9, 0x86, 0x48, 0x4a, - 0x8a, 0xf7, 0xcd, 0xb7, 0x18, 0x73, 0x41, 0xda, 0x4f, 0x1e, 0xb5, 0xd3, 0xc5, 0x57, 0x59, 0x93, - 0xf7, 0xb6, 0xf4, 0x27, 0xf2, 0xd1, 0x3f, 0x01, 0x00, 0x00, 0xff, 0xff, 0x36, 0x0b, 0xf0, 0xae, - 0xb4, 0x07, 0x00, 0x00, + // 832 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x56, 0xcf, 0x6f, 0xe3, 0x44, + 0x14, 0x8e, 0xe9, 0xd2, 0x4d, 0x27, 0x59, 0xd2, 0x9d, 0x2d, 0xa9, 0xb3, 0xa0, 0x38, 0xb2, 0x04, + 0x0a, 0x87, 0x26, 0xea, 0xee, 0x01, 0xa9, 0x17, 0xa4, 0xb4, 0x80, 0x2a, 0x40, 0x44, 0x6e, 0x01, + 0x89, 0x8b, 0x99, 0x4c, 0x46, 0xce, 0x80, 0x3d, 0x63, 0xcd, 0x4c, 0x5a, 0x07, 0x24, 0x0e, 0x48, + 0xdc, 0x11, 0x27, 0x04, 0x1c, 0xf6, 0xcc, 0x19, 0xf1, 0x37, 0xec, 0x71, 0xc5, 0x09, 0x38, 0x04, + 0xd4, 0x5e, 0x38, 0xe7, 0x2f, 0x40, 0x9e, 0x99, 0xfc, 0x32, 0xbb, 0xb0, 0xd1, 0x9e, 0x92, 0xf7, + 0xde, 0xf7, 0xbe, 0xef, 0x9b, 0x67, 0xfb, 0xd9, 0xe0, 0x15, 0x45, 0x84, 0x40, 0x5d, 0x25, 0x08, + 0x92, 0x63, 0x31, 0xe9, 0x5e, 0x1c, 0x0e, 0x88, 0x42, 0x87, 0x8b, 0x44, 0x27, 0x15, 0x5c, 0x71, + 0x58, 0xd7, 0xb0, 0xce, 0x22, 0x6b, 0x61, 0x77, 0x9b, 0x98, 0xcb, 0x84, 0xcb, 0xee, 0x00, 0x49, + 0xb2, 0xe8, 0xc5, 0x9c, 0x32, 0xd3, 0x77, 0xb7, 0x61, 0xea, 0xa1, 0x8e, 0xba, 0x26, 0xb0, 0xa5, + 0xbd, 0x88, 0x47, 0xdc, 0xe4, 0xf3, 0x7f, 0x26, 0xeb, 0xff, 0x5e, 0x06, 0xdb, 0x7d, 0x24, 0x50, + 0x22, 0x21, 0x06, 0x40, 0xa1, 0x2c, 0x4c, 0x79, 0x4c, 0xf1, 0xc4, 0x75, 0x5a, 0x4e, 0xbb, 0x72, + 0xef, 0xb5, 0xce, 0xe3, 0x8d, 0x74, 0xfa, 0x1a, 0x75, 0xcc, 0x99, 0x54, 0x02, 0x51, 0xa6, 0x64, + 0xaf, 0xf1, 0x70, 0xea, 0x95, 0x66, 0x53, 0xef, 0xf6, 0x04, 0x25, 0xf1, 0x91, 0xbf, 0xa4, 0xf2, + 0x83, 0x1d, 0x85, 0x32, 0xd3, 0x00, 0x63, 0x70, 0x4b, 0x90, 0x4b, 0x24, 0x86, 0x73, 0x9d, 0xe7, + 0x36, 0xd5, 0x79, 0xd9, 0xea, 0xec, 0x19, 0x9d, 0x35, 0x36, 0x3f, 0xa8, 0x9a, 0xd8, 0xaa, 0xfd, + 0xe8, 0x80, 0x86, 0x24, 0x34, 0x62, 0x94, 0x0b, 0x14, 0x91, 0x70, 0x30, 0x16, 0x43, 0xc2, 0x42, + 0x85, 0x44, 0x44, 0x94, 0xbb, 0xd5, 0x72, 0xda, 0x3b, 0xbd, 0x4f, 0x72, 0xbe, 0x3f, 0xa6, 0xde, + 0xab, 0x11, 0x55, 0xa3, 0xf1, 0xa0, 0x83, 0x79, 0x62, 0x07, 0x67, 0x7f, 0x0e, 0xe4, 0xf0, 0xb3, + 0xae, 0x9a, 0xa4, 0x44, 0x76, 0x4e, 0x08, 0x9e, 0x4d, 0xbd, 0x96, 0x51, 0x7e, 0x22, 0xb1, 0xff, + 0xeb, 0xcf, 0x07, 0xc0, 0xce, 0xfe, 0x84, 0xe0, 0x60, 0x7f, 0x05, 0xd9, 0xd3, 0xc0, 0x73, 0x8d, + 0x83, 0x5f, 0x39, 0x60, 0x37, 0xa1, 0x8c, 0xb2, 0x28, 0xa4, 0x0c, 0x0b, 0x92, 0x10, 0xa6, 0xdc, + 0x1b, 0xda, 0xd5, 0x47, 0x1b, 0xbb, 0xda, 0x37, 0xae, 0x8a, 0x7c, 0x45, 0x33, 0x35, 0x03, 0x38, + 0x9d, 0xd7, 0xe1, 0x11, 0xa8, 0x5e, 0x52, 0x36, 0xe4, 0x97, 0xa1, 0x1c, 0x71, 0xa1, 0xdc, 0xe7, + 0x5b, 0x4e, 0xfb, 0x46, 0x6f, 0x7f, 0x36, 0xf5, 0xee, 0x18, 0xc6, 0xd5, 0xaa, 0x1f, 0x54, 0x4c, + 0x78, 0x96, 0x47, 0xf0, 0x75, 0x60, 0xc3, 0x30, 0xe6, 0x2c, 0x72, 0xb7, 0x75, 0x6b, 0x7d, 0x36, + 0xf5, 0xe0, 0x5a, 0x6b, 0x5e, 0xf4, 0x03, 0x60, 0xa2, 0x77, 0x39, 0x8b, 0xe0, 0x5b, 0x60, 0xd7, + 0xd6, 0x52, 0xc1, 0x07, 0x48, 0x51, 0xce, 0xdc, 0x9b, 0xba, 0xfb, 0xa5, 0xe5, 0x51, 0x8a, 0x08, + 0x3f, 0xa8, 0x99, 0x54, 0x7f, 0x9e, 0x81, 0x5f, 0x80, 0x17, 0x06, 0x63, 0x91, 0x0f, 0x3e, 0x0b, + 0x65, 0x1a, 0x53, 0xe5, 0x96, 0xf5, 0xf8, 0x3e, 0xd8, 0x78, 0x7c, 0x2f, 0x1a, 0xcd, 0x75, 0xb6, + 0xe2, 0xf0, 0xaa, 0x79, 0xf9, 0x1c, 0x65, 0x67, 0x79, 0x11, 0xfe, 0xe0, 0x80, 0x46, 0x42, 0x59, + 0x48, 0x19, 0x55, 0x14, 0xc5, 0xe1, 0x90, 0xa4, 0x5c, 0x52, 0x15, 0x8a, 0xdc, 0x9b, 0xbb, 0xf3, + 0x6c, 0x77, 0xd7, 0x13, 0x89, 0x8b, 0x9e, 0xea, 0x09, 0x65, 0xa7, 0x06, 0x78, 0x62, 0x70, 0x41, + 0x0e, 0x83, 0x17, 0xa0, 0xca, 0x05, 0xc2, 0x31, 0xb1, 0x83, 0x01, 0xda, 0xcf, 0xd9, 0xc6, 0x7e, + 0xec, 0x5d, 0xb0, 0xca, 0x55, 0xb4, 0x50, 0x31, 0x45, 0x3d, 0x95, 0xa3, 0xf2, 0x77, 0x0f, 0xbc, + 0xd2, 0xdf, 0x0f, 0x3c, 0xc7, 0xff, 0x65, 0x0b, 0xdc, 0xfe, 0xd7, 0xf3, 0x0b, 0x3f, 0x05, 0x65, + 0x81, 0x14, 0x09, 0x13, 0xca, 0xf4, 0x92, 0xd9, 0xe9, 0xbd, 0xbf, 0xb1, 0xa7, 0x9a, 0x7d, 0xf6, + 0x2d, 0x4f, 0xd1, 0xcf, 0xcd, 0xbc, 0xf0, 0x1e, 0x65, 0x4b, 0x2d, 0x94, 0xe9, 0x45, 0xf3, 0xcc, + 0x5a, 0x28, 0x7b, 0xbc, 0x16, 0xca, 0xe0, 0x1b, 0x60, 0x0b, 0xa3, 0x54, 0x2f, 0x95, 0xca, 0xbd, + 0x46, 0xc7, 0x42, 0xf2, 0x45, 0xbd, 0x58, 0x66, 0xc7, 0x9c, 0xb2, 0x1e, 0xb4, 0xfb, 0x0b, 0x18, + 0x5e, 0x8c, 0x52, 0x3f, 0xc8, 0x3b, 0xe1, 0x97, 0xa0, 0x86, 0x47, 0x88, 0x45, 0x24, 0x5c, 0x78, + 0x36, 0xbb, 0xe0, 0xc3, 0x8d, 0x3d, 0xd7, 0x2d, 0xf7, 0x3a, 0x5d, 0xd1, 0xfa, 0x2d, 0x53, 0x0f, + 0xcc, 0x01, 0x56, 0x2e, 0xdc, 0xf7, 0x0e, 0xd8, 0x7d, 0x33, 0xe5, 0x78, 0x74, 0x8e, 0xb2, 0xbe, + 0xe0, 0x98, 0x90, 0xa1, 0x84, 0x5f, 0x3b, 0xa0, 0xaa, 0x97, 0xba, 0x4d, 0xb8, 0x4e, 0x6b, 0xeb, + 0xbf, 0x4f, 0xfa, 0xb6, 0x3d, 0xe9, 0x9d, 0x95, 0x37, 0x82, 0x6d, 0xf6, 0x7f, 0xfa, 0xd3, 0x6b, + 0x3f, 0xc5, 0x71, 0x72, 0x1e, 0x19, 0x54, 0xd4, 0xd2, 0x87, 0xff, 0xad, 0x03, 0xf6, 0xb4, 0x39, + 0x7b, 0xd3, 0x9f, 0x4a, 0x39, 0x46, 0x0c, 0x13, 0xf8, 0x39, 0x28, 0x53, 0xfb, 0xff, 0xff, 0xbd, + 0x1d, 0x5b, 0x6f, 0xf6, 0xea, 0xce, 0x1b, 0x37, 0xf3, 0xb5, 0xd0, 0xeb, 0xbd, 0xf3, 0xf0, 0xaa, + 0xe9, 0x3c, 0xba, 0x6a, 0x3a, 0x7f, 0x5d, 0x35, 0x9d, 0x6f, 0xae, 0x9b, 0xa5, 0x47, 0xd7, 0xcd, + 0xd2, 0x6f, 0xd7, 0xcd, 0xd2, 0xc7, 0x87, 0xab, 0x6c, 0x31, 0x92, 0x92, 0xe2, 0x03, 0xf3, 0x0d, + 0x80, 0xb9, 0x20, 0xdd, 0x8b, 0xfb, 0xdd, 0x6c, 0xf9, 0x35, 0xa0, 0xc9, 0x07, 0xdb, 0xfa, 0xd5, + 0x7c, 0xff, 0x9f, 0x00, 0x00, 0x00, 0xff, 0xff, 0xb0, 0x42, 0xe7, 0xc8, 0x2c, 0x08, 0x00, 0x00, } func (this *Params) Equal(that interface{}) bool { @@ -357,6 +359,9 @@ func (this *Params) Equal(that interface{}) bool { if !this.MinInitialDepositRatio.Equal(that1.MinInitialDepositRatio) { return false } + if !this.OracleSplit.Equal(that1.OracleSplit) { + return false + } return true } func (this *PolicyConstraints) Equal(that interface{}) bool { @@ -412,6 +417,16 @@ func (m *Params) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + { + size := m.OracleSplit.Size() + i -= size + if _, err := m.OracleSplit.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintTreasury(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x52 { size := m.MinInitialDepositRatio.Size() i -= size @@ -665,6 +680,8 @@ func (m *Params) Size() (n int) { n += 1 + l + sovTreasury(uint64(l)) l = m.MinInitialDepositRatio.Size() n += 1 + l + sovTreasury(uint64(l)) + l = m.OracleSplit.Size() + n += 1 + l + sovTreasury(uint64(l)) return n } @@ -1009,6 +1026,40 @@ func (m *Params) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 10: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field OracleSplit", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTreasury + } + 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 ErrInvalidLengthTreasury + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTreasury + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.OracleSplit.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipTreasury(dAtA[iNdEx:])