refactor: remove usage of global basedenom (#18268)
This commit is contained in:
parent
15ccdccea4
commit
e6a4c78e73
@ -185,6 +185,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
|
||||
* (x/mint) [#18283](https://github.com/cosmos/cosmos-sdk/pull/18283) Mint module was moved to its own go.mod `cosmossdk.io/x/mint`
|
||||
* (x/consensus) [#18041](https://github.com/cosmos/cosmos-sdk/pull/18041) `ToProtoConsensusParams()` returns an error
|
||||
* (x/slashing) [#18115](https://github.com/cosmos/cosmos-sdk/pull/18115) `NewValidatorSigningInfo` takes strings instead of `sdk.AccAddress`
|
||||
* (types) [#18268](https://github.com/cosmos/cosmos-sdk/pull/18268) Remove global setting of basedenom. Use the staking module parameter instead
|
||||
|
||||
### CLI Breaking Changes
|
||||
|
||||
|
||||
@ -881,7 +881,8 @@ func ParseCoinNormalized(coinStr string) (coin Coin, err error) {
|
||||
return Coin{}, err
|
||||
}
|
||||
|
||||
coin, _ = NormalizeDecCoin(decCoin).TruncateDecimal()
|
||||
coin, _ = NewDecCoinFromDec(decCoin.Denom, decCoin.Amount).TruncateDecimal()
|
||||
|
||||
return coin, nil
|
||||
}
|
||||
|
||||
@ -900,3 +901,20 @@ func ParseCoinsNormalized(coinStr string) (Coins, error) {
|
||||
}
|
||||
return NormalizeCoins(coins), nil
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// NormalizeCoins normalize and truncate a list of decimal coins
|
||||
func NormalizeCoins(coins []DecCoin) Coins {
|
||||
if coins == nil {
|
||||
return nil
|
||||
}
|
||||
result := make([]Coin, 0, len(coins))
|
||||
|
||||
for _, coin := range coins {
|
||||
newCoin, _ := NewDecCoinFromDec(coin.Denom, coin.Amount).TruncateDecimal()
|
||||
result = append(result, newCoin)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
160
types/denom.go
160
types/denom.go
@ -1,160 +0,0 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"cosmossdk.io/math"
|
||||
)
|
||||
|
||||
// denomUnits contains a mapping of denomination mapped to their respective unit
|
||||
// multipliers (e.g. 1atom = 10^-6uatom).
|
||||
var denomUnits = map[string]math.LegacyDec{}
|
||||
|
||||
// baseDenom is the denom of smallest unit registered
|
||||
var baseDenom string
|
||||
|
||||
// RegisterDenom registers a denomination with a corresponding unit. If the
|
||||
// denomination is already registered, an error will be returned.
|
||||
func RegisterDenom(denom string, unit math.LegacyDec) error {
|
||||
if err := ValidateDenom(denom); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, ok := denomUnits[denom]; ok {
|
||||
return fmt.Errorf("denom %s already registered", denom)
|
||||
}
|
||||
|
||||
denomUnits[denom] = unit
|
||||
|
||||
if baseDenom == "" || unit.LT(denomUnits[baseDenom]) {
|
||||
baseDenom = denom
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetDenomUnit returns a unit for a given denomination if it exists. A boolean
|
||||
// is returned if the denomination is registered.
|
||||
func GetDenomUnit(denom string) (math.LegacyDec, bool) {
|
||||
if err := ValidateDenom(denom); err != nil {
|
||||
return math.LegacyZeroDec(), false
|
||||
}
|
||||
|
||||
unit, ok := denomUnits[denom]
|
||||
if !ok {
|
||||
return math.LegacyZeroDec(), false
|
||||
}
|
||||
|
||||
return unit, true
|
||||
}
|
||||
|
||||
// SetBaseDenom allow overwritting the base denom
|
||||
// if the denom has registered before, otherwise return error
|
||||
func SetBaseDenom(denom string) error {
|
||||
_, ok := denomUnits[denom]
|
||||
if !ok {
|
||||
return fmt.Errorf("denom %s not registered", denom)
|
||||
}
|
||||
baseDenom = denom
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetBaseDenom returns the denom of smallest unit registered
|
||||
func GetBaseDenom() (string, error) {
|
||||
if baseDenom == "" {
|
||||
return "", fmt.Errorf("no denom is registered")
|
||||
}
|
||||
return baseDenom, nil
|
||||
}
|
||||
|
||||
// ConvertCoin attempts to convert a coin to a given denomination. If the given
|
||||
// denomination is invalid or if neither denomination is registered, an error
|
||||
// is returned.
|
||||
func ConvertCoin(coin Coin, denom string) (Coin, error) {
|
||||
if err := ValidateDenom(denom); err != nil {
|
||||
return Coin{}, err
|
||||
}
|
||||
|
||||
srcUnit, ok := GetDenomUnit(coin.Denom)
|
||||
if !ok {
|
||||
return Coin{}, fmt.Errorf("source denom not registered: %s", coin.Denom)
|
||||
}
|
||||
|
||||
dstUnit, ok := GetDenomUnit(denom)
|
||||
if !ok {
|
||||
return Coin{}, fmt.Errorf("destination denom not registered: %s", denom)
|
||||
}
|
||||
|
||||
if srcUnit.Equal(dstUnit) {
|
||||
return NewCoin(denom, coin.Amount), nil
|
||||
}
|
||||
|
||||
return NewCoin(denom, math.LegacyNewDecFromInt(coin.Amount).Mul(srcUnit).Quo(dstUnit).TruncateInt()), nil
|
||||
}
|
||||
|
||||
// ConvertDecCoin attempts to convert a decimal coin to a given denomination. If the given
|
||||
// denomination is invalid or if neither denomination is registered, an error
|
||||
// is returned.
|
||||
func ConvertDecCoin(coin DecCoin, denom string) (DecCoin, error) {
|
||||
if err := ValidateDenom(denom); err != nil {
|
||||
return DecCoin{}, err
|
||||
}
|
||||
|
||||
srcUnit, ok := GetDenomUnit(coin.Denom)
|
||||
if !ok {
|
||||
return DecCoin{}, fmt.Errorf("source denom not registered: %s", coin.Denom)
|
||||
}
|
||||
|
||||
dstUnit, ok := GetDenomUnit(denom)
|
||||
if !ok {
|
||||
return DecCoin{}, fmt.Errorf("destination denom not registered: %s", denom)
|
||||
}
|
||||
|
||||
if srcUnit.Equal(dstUnit) {
|
||||
return NewDecCoinFromDec(denom, coin.Amount), nil
|
||||
}
|
||||
|
||||
return NewDecCoinFromDec(denom, coin.Amount.Mul(srcUnit).Quo(dstUnit)), nil
|
||||
}
|
||||
|
||||
// NormalizeCoin try to convert a coin to the smallest unit registered,
|
||||
// returns original one if failed.
|
||||
func NormalizeCoin(coin Coin) Coin {
|
||||
base, err := GetBaseDenom()
|
||||
if err != nil {
|
||||
return coin
|
||||
}
|
||||
newCoin, err := ConvertCoin(coin, base)
|
||||
if err != nil {
|
||||
return coin
|
||||
}
|
||||
return newCoin
|
||||
}
|
||||
|
||||
// NormalizeDecCoin try to convert a decimal coin to the smallest unit registered,
|
||||
// returns original one if failed.
|
||||
func NormalizeDecCoin(coin DecCoin) DecCoin {
|
||||
base, err := GetBaseDenom()
|
||||
if err != nil {
|
||||
return coin
|
||||
}
|
||||
newCoin, err := ConvertDecCoin(coin, base)
|
||||
if err != nil {
|
||||
return coin
|
||||
}
|
||||
return newCoin
|
||||
}
|
||||
|
||||
// NormalizeCoins normalize and truncate a list of decimal coins
|
||||
func NormalizeCoins(coins []DecCoin) Coins {
|
||||
if coins == nil {
|
||||
return nil
|
||||
}
|
||||
result := make([]Coin, 0, len(coins))
|
||||
|
||||
for _, coin := range coins {
|
||||
newCoin, _ := NormalizeDecCoin(coin).TruncateDecimal()
|
||||
result = append(result, newCoin)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
@ -1,211 +0,0 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/suite"
|
||||
|
||||
"cosmossdk.io/math"
|
||||
)
|
||||
|
||||
var (
|
||||
atom = "atom" // 1 (base denom unit)
|
||||
matom = "matom" // 10^-3 (milli)
|
||||
uatom = "uatom" // 10^-6 (micro)
|
||||
natom = "natom" // 10^-9 (nano)
|
||||
)
|
||||
|
||||
type internalDenomTestSuite struct {
|
||||
suite.Suite
|
||||
}
|
||||
|
||||
func TestInternalDenomTestSuite(t *testing.T) {
|
||||
suite.Run(t, new(internalDenomTestSuite))
|
||||
}
|
||||
|
||||
func (s *internalDenomTestSuite) TestRegisterDenom() {
|
||||
atomUnit := math.LegacyOneDec() // 1 (base denom unit)
|
||||
|
||||
s.Require().NoError(RegisterDenom(atom, atomUnit))
|
||||
s.Require().Error(RegisterDenom(atom, atomUnit))
|
||||
|
||||
res, ok := GetDenomUnit(atom)
|
||||
s.Require().True(ok)
|
||||
s.Require().Equal(atomUnit, res)
|
||||
|
||||
res, ok = GetDenomUnit(matom)
|
||||
s.Require().False(ok)
|
||||
s.Require().Equal(math.LegacyZeroDec(), res)
|
||||
|
||||
err := SetBaseDenom(atom)
|
||||
s.Require().NoError(err)
|
||||
|
||||
res, ok = GetDenomUnit(atom)
|
||||
s.Require().True(ok)
|
||||
s.Require().Equal(atomUnit, res)
|
||||
|
||||
// reset registration
|
||||
baseDenom = ""
|
||||
denomUnits = map[string]math.LegacyDec{}
|
||||
}
|
||||
|
||||
func (s *internalDenomTestSuite) TestConvertCoins() {
|
||||
atomUnit := math.LegacyOneDec() // 1 (base denom unit)
|
||||
s.Require().NoError(RegisterDenom(atom, atomUnit))
|
||||
|
||||
matomUnit := math.LegacyNewDecWithPrec(1, 3) // 10^-3 (milli)
|
||||
s.Require().NoError(RegisterDenom(matom, matomUnit))
|
||||
|
||||
uatomUnit := math.LegacyNewDecWithPrec(1, 6) // 10^-6 (micro)
|
||||
s.Require().NoError(RegisterDenom(uatom, uatomUnit))
|
||||
|
||||
natomUnit := math.LegacyNewDecWithPrec(1, 9) // 10^-9 (nano)
|
||||
s.Require().NoError(RegisterDenom(natom, natomUnit))
|
||||
|
||||
res, err := GetBaseDenom()
|
||||
s.Require().NoError(err)
|
||||
s.Require().Equal(res, natom)
|
||||
s.Require().Equal(NormalizeCoin(NewCoin(uatom, math.NewInt(1))), NewCoin(natom, math.NewInt(1000)))
|
||||
s.Require().Equal(NormalizeCoin(NewCoin(matom, math.NewInt(1))), NewCoin(natom, math.NewInt(1000000)))
|
||||
s.Require().Equal(NormalizeCoin(NewCoin(atom, math.NewInt(1))), NewCoin(natom, math.NewInt(1000000000)))
|
||||
|
||||
coins, err := ParseCoinsNormalized("1atom,1matom,1uatom")
|
||||
s.Require().NoError(err)
|
||||
s.Require().Equal(coins, Coins{
|
||||
Coin{natom, math.NewInt(1000000000)},
|
||||
Coin{natom, math.NewInt(1000000)},
|
||||
Coin{natom, math.NewInt(1000)},
|
||||
})
|
||||
|
||||
testCases := []struct {
|
||||
input Coin
|
||||
denom string
|
||||
result Coin
|
||||
expErr bool
|
||||
}{
|
||||
{NewCoin("foo", math.ZeroInt()), atom, Coin{}, true},
|
||||
{NewCoin(atom, math.ZeroInt()), "foo", Coin{}, true},
|
||||
{NewCoin(atom, math.ZeroInt()), "FOO", Coin{}, true},
|
||||
|
||||
{NewCoin(atom, math.NewInt(5)), matom, NewCoin(matom, math.NewInt(5000)), false}, // atom => matom
|
||||
{NewCoin(atom, math.NewInt(5)), uatom, NewCoin(uatom, math.NewInt(5000000)), false}, // atom => uatom
|
||||
{NewCoin(atom, math.NewInt(5)), natom, NewCoin(natom, math.NewInt(5000000000)), false}, // atom => natom
|
||||
|
||||
{NewCoin(uatom, math.NewInt(5000000)), matom, NewCoin(matom, math.NewInt(5000)), false}, // uatom => matom
|
||||
{NewCoin(uatom, math.NewInt(5000000)), natom, NewCoin(natom, math.NewInt(5000000000)), false}, // uatom => natom
|
||||
{NewCoin(uatom, math.NewInt(5000000)), atom, NewCoin(atom, math.NewInt(5)), false}, // uatom => atom
|
||||
|
||||
{NewCoin(matom, math.NewInt(5000)), natom, NewCoin(natom, math.NewInt(5000000000)), false}, // matom => natom
|
||||
{NewCoin(matom, math.NewInt(5000)), uatom, NewCoin(uatom, math.NewInt(5000000)), false}, // matom => uatom
|
||||
}
|
||||
|
||||
for i, tc := range testCases {
|
||||
res, err := ConvertCoin(tc.input, tc.denom)
|
||||
s.Require().Equal(
|
||||
tc.expErr, err != nil,
|
||||
"unexpected error; tc: #%d, input: %s, denom: %s", i+1, tc.input, tc.denom,
|
||||
)
|
||||
s.Require().Equal(
|
||||
tc.result, res,
|
||||
"invalid result; tc: #%d, input: %s, denom: %s", i+1, tc.input, tc.denom,
|
||||
)
|
||||
}
|
||||
|
||||
// reset registration
|
||||
baseDenom = ""
|
||||
denomUnits = map[string]math.LegacyDec{}
|
||||
}
|
||||
|
||||
func (s *internalDenomTestSuite) TestConvertDecCoins() {
|
||||
atomUnit := math.LegacyOneDec() // 1 (base denom unit)
|
||||
s.Require().NoError(RegisterDenom(atom, atomUnit))
|
||||
|
||||
matomUnit := math.LegacyNewDecWithPrec(1, 3) // 10^-3 (milli)
|
||||
s.Require().NoError(RegisterDenom(matom, matomUnit))
|
||||
|
||||
uatomUnit := math.LegacyNewDecWithPrec(1, 6) // 10^-6 (micro)
|
||||
s.Require().NoError(RegisterDenom(uatom, uatomUnit))
|
||||
|
||||
natomUnit := math.LegacyNewDecWithPrec(1, 9) // 10^-9 (nano)
|
||||
s.Require().NoError(RegisterDenom(natom, natomUnit))
|
||||
|
||||
res, err := GetBaseDenom()
|
||||
s.Require().NoError(err)
|
||||
s.Require().Equal(res, natom)
|
||||
s.Require().Equal(NormalizeDecCoin(NewDecCoin(uatom, math.NewInt(1))), NewDecCoin(natom, math.NewInt(1000)))
|
||||
s.Require().Equal(NormalizeDecCoin(NewDecCoin(matom, math.NewInt(1))), NewDecCoin(natom, math.NewInt(1000000)))
|
||||
s.Require().Equal(NormalizeDecCoin(NewDecCoin(atom, math.NewInt(1))), NewDecCoin(natom, math.NewInt(1000000000)))
|
||||
|
||||
coins, err := ParseCoinsNormalized("0.1atom,0.1matom,0.1uatom")
|
||||
s.Require().NoError(err)
|
||||
s.Require().Equal(coins, Coins{
|
||||
Coin{natom, math.NewInt(100000000)},
|
||||
Coin{natom, math.NewInt(100000)},
|
||||
Coin{natom, math.NewInt(100)},
|
||||
})
|
||||
|
||||
testCases := []struct {
|
||||
input DecCoin
|
||||
denom string
|
||||
result DecCoin
|
||||
expErr bool
|
||||
}{
|
||||
{NewDecCoin("foo", math.ZeroInt()), atom, DecCoin{}, true},
|
||||
{NewDecCoin(atom, math.ZeroInt()), "foo", DecCoin{}, true},
|
||||
{NewDecCoin(atom, math.ZeroInt()), "FOO", DecCoin{}, true},
|
||||
|
||||
// 0.5atom
|
||||
{NewDecCoinFromDec(atom, math.LegacyNewDecWithPrec(5, 1)), matom, NewDecCoin(matom, math.NewInt(500)), false}, // atom => matom
|
||||
{NewDecCoinFromDec(atom, math.LegacyNewDecWithPrec(5, 1)), uatom, NewDecCoin(uatom, math.NewInt(500000)), false}, // atom => uatom
|
||||
{NewDecCoinFromDec(atom, math.LegacyNewDecWithPrec(5, 1)), natom, NewDecCoin(natom, math.NewInt(500000000)), false}, // atom => natom
|
||||
|
||||
{NewDecCoin(uatom, math.NewInt(5000000)), matom, NewDecCoin(matom, math.NewInt(5000)), false}, // uatom => matom
|
||||
{NewDecCoin(uatom, math.NewInt(5000000)), natom, NewDecCoin(natom, math.NewInt(5000000000)), false}, // uatom => natom
|
||||
{NewDecCoin(uatom, math.NewInt(5000000)), atom, NewDecCoin(atom, math.NewInt(5)), false}, // uatom => atom
|
||||
|
||||
{NewDecCoin(matom, math.NewInt(5000)), natom, NewDecCoin(natom, math.NewInt(5000000000)), false}, // matom => natom
|
||||
{NewDecCoin(matom, math.NewInt(5000)), uatom, NewDecCoin(uatom, math.NewInt(5000000)), false}, // matom => uatom
|
||||
}
|
||||
|
||||
for i, tc := range testCases {
|
||||
res, err := ConvertDecCoin(tc.input, tc.denom)
|
||||
s.Require().Equal(
|
||||
tc.expErr, err != nil,
|
||||
"unexpected error; tc: #%d, input: %s, denom: %s", i+1, tc.input, tc.denom,
|
||||
)
|
||||
s.Require().Equal(
|
||||
tc.result, res,
|
||||
"invalid result; tc: #%d, input: %s, denom: %s", i+1, tc.input, tc.denom,
|
||||
)
|
||||
}
|
||||
|
||||
// reset registration
|
||||
baseDenom = ""
|
||||
denomUnits = map[string]math.LegacyDec{}
|
||||
}
|
||||
|
||||
func (s *internalDenomTestSuite) TestDecOperationOrder() {
|
||||
dec, err := math.LegacyNewDecFromStr("11")
|
||||
s.Require().NoError(err)
|
||||
s.Require().NoError(RegisterDenom("unit1", dec))
|
||||
dec, err = math.LegacyNewDecFromStr("100000011")
|
||||
s.Require().NoError(err)
|
||||
s.Require().NoError(RegisterDenom("unit2", dec))
|
||||
|
||||
coin, err := ConvertCoin(NewCoin("unit1", math.NewInt(100000011)), "unit2")
|
||||
s.Require().NoError(err)
|
||||
s.Require().Equal(coin, NewCoin("unit2", math.NewInt(11)))
|
||||
|
||||
// reset registration
|
||||
baseDenom = ""
|
||||
denomUnits = map[string]math.LegacyDec{}
|
||||
}
|
||||
|
||||
func (s *internalDenomTestSuite) TestSetBaseDenomError() {
|
||||
err := SetBaseDenom(atom)
|
||||
s.Require().Error(err)
|
||||
|
||||
// reset registration
|
||||
baseDenom = ""
|
||||
denomUnits = map[string]math.LegacyDec{}
|
||||
}
|
||||
@ -301,9 +301,9 @@ func (k Keeper) withdrawDelegationRewards(ctx context.Context, val stakingtypes.
|
||||
}
|
||||
|
||||
if finalRewards.IsZero() {
|
||||
baseDenom, _ := sdk.GetBaseDenom()
|
||||
if baseDenom == "" {
|
||||
baseDenom = sdk.DefaultBondDenom
|
||||
baseDenom, err := k.stakingKeeper.BondDenom(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Note, we do not call the NewCoins constructor as we do not want the zero
|
||||
|
||||
@ -1006,6 +1006,7 @@ func Test100PercentCommissionReward(t *testing.T) {
|
||||
|
||||
accountKeeper.EXPECT().GetModuleAddress("distribution").Return(distrAcc.GetAddress())
|
||||
stakingKeeper.EXPECT().ValidatorAddressCodec().Return(address.NewBech32Codec(sdk.Bech32PrefixValAddr)).AnyTimes()
|
||||
stakingKeeper.EXPECT().BondDenom(gomock.Any()).Return("stake", nil).AnyTimes()
|
||||
accountKeeper.EXPECT().AddressCodec().Return(address.NewBech32Codec(sdk.Bech32MainPrefix)).AnyTimes()
|
||||
|
||||
distrKeeper := keeper.NewKeeper(
|
||||
|
||||
@ -315,6 +315,21 @@ func (m *MockStakingKeeper) EXPECT() *MockStakingKeeperMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// BondDenom mocks base method.
|
||||
func (m *MockStakingKeeper) BondDenom(ctx context.Context) (string, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "BondDenom", ctx)
|
||||
ret0, _ := ret[0].(string)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// BondDenom indicates an expected call of BondDenom.
|
||||
func (mr *MockStakingKeeperMockRecorder) BondDenom(ctx interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BondDenom", reflect.TypeOf((*MockStakingKeeper)(nil).BondDenom), ctx)
|
||||
}
|
||||
|
||||
// ConsensusAddressCodec mocks base method.
|
||||
func (m *MockStakingKeeper) ConsensusAddressCodec() address.Codec {
|
||||
m.ctrl.T.Helper()
|
||||
|
||||
@ -44,6 +44,8 @@ type PoolKeeper interface {
|
||||
type StakingKeeper interface {
|
||||
ValidatorAddressCodec() address.Codec
|
||||
ConsensusAddressCodec() address.Codec
|
||||
BondDenom(ctx context.Context) (string, error)
|
||||
|
||||
// iterate through validators by operator address, execute func for each validator
|
||||
IterateValidators(context.Context,
|
||||
func(index int64, validator stakingtypes.ValidatorI) (stop bool)) error
|
||||
|
||||
Loading…
Reference in New Issue
Block a user