From 31ef3afb9a17b988b04fed491fa87de8e27469ce Mon Sep 17 00:00:00 2001 From: Prathamesh Musale Date: Tue, 13 May 2025 12:37:11 +0000 Subject: [PATCH] Add a new token and only allow fees in alnt (#68) Part of https://www.notion.so/Multiple-tokens-support-and-disable-transfers-for-LSTAKE-1f2a6b22d47280269f87df3fe03e8d64 - Add base token with denoms `alps` and `lps` (`1 lps = 10^18 alps`) - Keep `alnt` as the staking token and for laconic module ops - Accept tx fees only in `alnt` Reviewed-on: https://git.vdb.to/cerc-io/laconicd/pulls/68 Co-authored-by: Prathamesh Musale Co-committed-by: Prathamesh Musale --- app/ante.go | 79 ++++++++++++++++++++++++++++++ app/app.go | 24 +++++++++ app/params/config.go | 16 +++--- cmd/laconicd/cmd/root.go | 4 +- scripts/init.sh | 9 ++-- x/bond/params.go | 5 +- x/registry/keeper/naming_keeper.go | 3 +- x/registry/params.go | 22 +++++---- 8 files changed, 136 insertions(+), 26 deletions(-) create mode 100644 app/ante.go diff --git a/app/ante.go b/app/ante.go new file mode 100644 index 000000000..074fdeb06 --- /dev/null +++ b/app/ante.go @@ -0,0 +1,79 @@ +package app + +import ( + _ "embed" + "math" + + errorsmod "cosmossdk.io/errors" + sdkmath "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + + "git.vdb.to/cerc-io/laconicd/app/params" +) + +// Reference: https://github.com/cosmos/cosmos-sdk/blob/v0.50.10/x/auth/ante/validator_tx_fee.go#L15 + +// checkTxFeeWithValidatorMinGasPrices 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. +func checkTxFeeWithValidatorMinGasPrices(ctx sdk.Context, tx sdk.Tx) (sdk.Coins, int64, error) { + feeTx, ok := tx.(sdk.FeeTx) + if !ok { + return nil, 0, errorsmod.Wrap(sdkerrors.ErrTxDecode, "Tx must be a FeeTx") + } + + feeCoins := feeTx.GetFee() + gas := feeTx.GetGas() + + // Only allow alnt as a fee token + for _, coin := range feeCoins { + if coin.Denom != params.CoinUnit { + return nil, 0, errorsmod.Wrapf(sdkerrors.ErrInvalidCoins, "invalid fee denom %s, only %s is accepted", coin.Denom, params.CoinUnit) + } + } + + // 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() { + minGasPrices := ctx.MinGasPrices() + if !minGasPrices.IsZero() { + requiredFees := 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 := sdkmath.LegacyNewDec(int64(gas)) + for i, gp := range minGasPrices { + fee := gp.Amount.Mul(glDec) + requiredFees[i] = sdk.NewCoin(gp.Denom, fee.Ceil().RoundInt()) + } + + if !feeCoins.IsAnyGTE(requiredFees) { + return nil, 0, errorsmod.Wrapf(sdkerrors.ErrInsufficientFee, "insufficient fees; got: %s required: %s", feeCoins, requiredFees) + } + } + } + + priority := getTxPriority(feeCoins, int64(gas)) + return feeCoins, 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/app/app.go b/app/app.go index 98dba6499..08d39552d 100644 --- a/app/app.go +++ b/app/app.go @@ -27,6 +27,7 @@ import ( "github.com/cosmos/cosmos-sdk/server/config" servertypes "github.com/cosmos/cosmos-sdk/server/types" "github.com/cosmos/cosmos-sdk/types/module" + "github.com/cosmos/cosmos-sdk/x/auth/ante" authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper" bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" consensuskeeper "github.com/cosmos/cosmos-sdk/x/consensus/keeper" @@ -185,6 +186,9 @@ func NewLaconicApp( app.sm = module.NewSimulationManagerFromAppModules(app.ModuleManager.Modules, make(map[string]module.AppModuleSimulation, 0)) app.sm.RegisterStoreDecoders() + // set custom ante handlers + app.setCustomAnteHandler() + if err := app.Load(loadLatest); err != nil { return nil, err } @@ -232,3 +236,23 @@ func (app *LaconicApp) RegisterAPIRoutes(apiSvr *api.Server, apiConfig config.AP panic(err) } } + +// setCustomAnteHandler overwrites default ante handlers with custom ante handlers +// Reference: https://github.com/cosmos/cosmos-sdk/blob/v0.50.10/x/auth/tx/config/config.go#L149 +func (app *LaconicApp) setCustomAnteHandler() { + anteHandler, err := ante.NewAnteHandler( + ante.HandlerOptions{ + AccountKeeper: app.AccountKeeper, + BankKeeper: app.BankKeeper, + SignModeHandler: app.txConfig.SignModeHandler(), + SigGasConsumer: ante.DefaultSigVerificationGasConsumer, + TxFeeChecker: checkTxFeeWithValidatorMinGasPrices, + }, + ) + if err != nil { + panic(err) + } + + // Set the AnteHandler for the app + app.SetAnteHandler(anteHandler) +} diff --git a/app/params/config.go b/app/params/config.go index 77c8747dd..6e7289341 100644 --- a/app/params/config.go +++ b/app/params/config.go @@ -10,11 +10,14 @@ import ( ) const ( - CoinUnit = "lnt" - BaseCoinUnit = "alnt" - LntExponent = 18 + // Registered token + LpsCoinUnit = "lps" + LpsBaseCoinUnit = "alps" + LpsExponent = 18 - DefaultBondDenom = BaseCoinUnit + // Native token, only denominated in alnt + // Used for staking, fees and laconic module ops + CoinUnit = "alnt" // Bech32PrefixAccAddr defines the Bech32 prefix of an account's address. Bech32PrefixAccAddr = "laconic" @@ -39,12 +42,11 @@ func init() { } func RegisterDenoms() { - err := sdk.RegisterDenom(CoinUnit, math.LegacyOneDec()) + err := sdk.RegisterDenom(LpsCoinUnit, math.LegacyOneDec()) if err != nil { panic(err) } - - err = sdk.RegisterDenom(BaseCoinUnit, math.LegacyNewDecWithPrec(1, LntExponent)) + err = sdk.RegisterDenom(LpsBaseCoinUnit, math.LegacyNewDecWithPrec(1, LpsExponent)) if err != nil { panic(err) } diff --git a/cmd/laconicd/cmd/root.go b/cmd/laconicd/cmd/root.go index af1cd19e6..957973e1d 100644 --- a/cmd/laconicd/cmd/root.go +++ b/cmd/laconicd/cmd/root.go @@ -21,7 +21,6 @@ import ( "github.com/cosmos/cosmos-sdk/crypto/keyring" "github.com/cosmos/cosmos-sdk/server" serverconfig "github.com/cosmos/cosmos-sdk/server/config" - sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/module" "github.com/cosmos/cosmos-sdk/types/tx/signing" "github.com/cosmos/cosmos-sdk/x/auth/tx" @@ -29,6 +28,7 @@ import ( "github.com/cosmos/cosmos-sdk/x/auth/types" "git.vdb.to/cerc-io/laconicd/app" + "git.vdb.to/cerc-io/laconicd/app/params" "git.vdb.to/cerc-io/laconicd/gql" ) @@ -100,7 +100,7 @@ func NewRootCmd() *cobra.Command { // overwrite the minimum gas price from the app configuration srvCfg := serverconfig.DefaultConfig() - srvCfg.MinGasPrices = fmt.Sprintf("0%s", sdk.DefaultBondDenom) + srvCfg.MinGasPrices = fmt.Sprintf("0%s", params.CoinUnit) // overwrite the block timeout cmtCfg := cmtcfg.DefaultConfig() diff --git a/scripts/init.sh b/scripts/init.sh index 06d7fae8b..30db16d9e 100755 --- a/scripts/init.sh +++ b/scripts/init.sh @@ -1,11 +1,14 @@ #!/bin/bash +set -e + KEY="alice" CHAINID=${CHAINID:-"laconic_9000-1"} MONIKER=${MONIKER:-"localtestnet"} KEYRING=${KEYRING:-"test"} DENOM=${DENOM:-"alnt"} -STAKING_AMOUNT=${STAKING_AMOUNT:-"1000000000000000"} +BALANCE=${BALANCE:-"1000000000000000000000000000000"} # 10^32 alnt +STAKING_AMOUNT=${STAKING_AMOUNT:-"1000000000000000"} # 10^15 alnt MIN_GAS_PRICE=${MIN_GAS_PRICE:-"0.001"} LOGLEVEL=${LOGLEVEL:-"info"} @@ -126,11 +129,9 @@ if [ "$1" == "clean" ] || [ ! -d "$HOME/.laconicd/data" ]; then fi # Allocate genesis accounts (cosmos formatted addresses) - # 10^30 alnt | 10^12 lnt - laconicd genesis add-genesis-account $KEY 1000000000000000000000000000000$DENOM --keyring-backend $KEYRING + laconicd genesis add-genesis-account $KEY ${BALANCE}${DENOM} --keyring-backend $KEYRING # Sign genesis transaction - # 10^15 alnt laconicd genesis gentx $KEY $STAKING_AMOUNT$DENOM --keyring-backend $KEYRING --chain-id $CHAINID # Collect genesis tx diff --git a/x/bond/params.go b/x/bond/params.go index 12901561d..ea65c45e6 100644 --- a/x/bond/params.go +++ b/x/bond/params.go @@ -5,11 +5,12 @@ import ( fmt "fmt" sdkmath "cosmossdk.io/math" + "git.vdb.to/cerc-io/laconicd/app/params" sdk "github.com/cosmos/cosmos-sdk/types" ) // DefaultMaxBondAmountTokens are the default parameter values. -var DefaultMaxBondAmountTokens = sdkmath.NewInt(1000000000000) // 10^12 alnt +var DefaultMaxBondAmountTokens = sdkmath.NewInt(1000000000000) // 10^12 func NewParams(maxBondAmount sdk.Coin) Params { return Params{MaxBondAmount: maxBondAmount} @@ -17,7 +18,7 @@ func NewParams(maxBondAmount sdk.Coin) Params { // DefaultParams returns default module parameters func DefaultParams() Params { - return NewParams(sdk.NewCoin(sdk.DefaultBondDenom, DefaultMaxBondAmountTokens)) + return NewParams(sdk.NewCoin(params.CoinUnit, DefaultMaxBondAmountTokens)) } // Validate checks that the parameters have valid values diff --git a/x/registry/keeper/naming_keeper.go b/x/registry/keeper/naming_keeper.go index 660173cd2..096d12720 100644 --- a/x/registry/keeper/naming_keeper.go +++ b/x/registry/keeper/naming_keeper.go @@ -15,6 +15,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "git.vdb.to/cerc-io/laconicd/app/params" auctiontypes "git.vdb.to/cerc-io/laconicd/x/auction" registrytypes "git.vdb.to/cerc-io/laconicd/x/registry" "git.vdb.to/cerc-io/laconicd/x/registry/helpers" @@ -295,7 +296,7 @@ func (k Keeper) createAuthority(ctx sdk.Context, name string, owner string, isRo moduleParams.AuthorityAuctionCommitFee, moduleParams.AuthorityAuctionRevealFee, moduleParams.AuthorityAuctionMinimumBid, - sdk.NewCoin(sdk.DefaultBondDenom, math.NewInt(0)), + sdk.NewCoin(params.CoinUnit, math.NewInt(0)), 0, ownerAddress, ) diff --git a/x/registry/params.go b/x/registry/params.go index 31c8700d9..1a794a202 100644 --- a/x/registry/params.go +++ b/x/registry/params.go @@ -6,26 +6,28 @@ import ( sdkmath "cosmossdk.io/math" sdk "github.com/cosmos/cosmos-sdk/types" + + "git.vdb.to/cerc-io/laconicd/app/params" ) // Default parameter values. var ( // DefaultRecordRent is the default record rent for 1 time period (see expiry time). - DefaultRecordRent = sdkmath.NewInt(1000000) // 10^6 alnt + DefaultRecordRent = sdkmath.NewInt(1000000) // 10^6 // DefaultRecordExpiryTime is the default record expiry time (1 year). DefaultRecordExpiryTime = time.Hour * 24 * 365 - DefaultAuthorityRent = sdkmath.NewInt(1000000) // 10^6 alnt + DefaultAuthorityRent = sdkmath.NewInt(1000000) // 10^6 DefaultAuthorityExpiryTime = time.Hour * 24 * 365 DefaultAuthorityGracePeriod = time.Hour * 24 * 2 DefaultAuthorityAuctionEnabled = false DefaultCommitsDuration = time.Hour * 24 DefaultRevealsDuration = time.Hour * 24 - DefaultCommitFee = sdkmath.NewInt(1000000) // 10^6 alnt - DefaultRevealFee = sdkmath.NewInt(1000000) // 10^6 alnt - DefaultMinimumBid = sdkmath.NewInt(5000000) // 5 * 10^6 alnt + DefaultCommitFee = sdkmath.NewInt(1000000) // 10^6 + DefaultRevealFee = sdkmath.NewInt(1000000) // 10^6 + DefaultMinimumBid = sdkmath.NewInt(5000000) // 5 * 10^6 ) // NewParams creates a new Params instance @@ -60,13 +62,13 @@ func NewParams( // DefaultParams returns a default set of parameters. func DefaultParams() Params { return NewParams( - sdk.NewCoin(sdk.DefaultBondDenom, DefaultRecordRent), DefaultRecordExpiryTime, - sdk.NewCoin(sdk.DefaultBondDenom, DefaultAuthorityRent), + sdk.NewCoin(params.CoinUnit, DefaultRecordRent), DefaultRecordExpiryTime, + sdk.NewCoin(params.CoinUnit, DefaultAuthorityRent), DefaultAuthorityExpiryTime, DefaultAuthorityGracePeriod, DefaultAuthorityAuctionEnabled, DefaultCommitsDuration, DefaultRevealsDuration, - sdk.NewCoin(sdk.DefaultBondDenom, DefaultCommitFee), - sdk.NewCoin(sdk.DefaultBondDenom, DefaultRevealFee), - sdk.NewCoin(sdk.DefaultBondDenom, DefaultMinimumBid), + sdk.NewCoin(params.CoinUnit, DefaultCommitFee), + sdk.NewCoin(params.CoinUnit, DefaultRevealFee), + sdk.NewCoin(params.CoinUnit, DefaultMinimumBid), ) }