Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: emergency group index update #2246

Merged
merged 12 commits into from
Sep 27, 2023
1 change: 1 addition & 0 deletions app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -506,6 +506,7 @@ func New(
app.BankKeeper,
app.LeverageKeeper,
app.OracleKeeper,
app.UGovKeeperB.EmergencyGroup,
)
}

Expand Down
6 changes: 6 additions & 0 deletions x/metoken/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
storetypes "github.com/cosmos/cosmos-sdk/store/types"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/tendermint/tendermint/libs/log"
"github.com/umee-network/umee/v6/x/ugov"

"github.com/umee-network/umee/v6/x/metoken"
)
Expand All @@ -16,6 +17,7 @@ type Builder struct {
bankKeeper metoken.BankKeeper
leverageKeeper metoken.LeverageKeeper
oracleKeeper metoken.OracleKeeper
ugov ugov.EmergencyGroupBuilder
}

// NewKeeperBuilder returns Builder object.
Expand All @@ -25,13 +27,15 @@ func NewKeeperBuilder(
bankKeeper metoken.BankKeeper,
leverageKeeper metoken.LeverageKeeper,
oracleKeeper metoken.OracleKeeper,
ugov ugov.EmergencyGroupBuilder,
) Builder {
return Builder{
cdc: cdc,
storeKey: storeKey,
bankKeeper: bankKeeper,
leverageKeeper: leverageKeeper,
oracleKeeper: oracleKeeper,
ugov: ugov,
}
}

Expand All @@ -41,6 +45,7 @@ type Keeper struct {
bankKeeper metoken.BankKeeper
leverageKeeper metoken.LeverageKeeper
oracleKeeper metoken.OracleKeeper
ugov ugov.EmergencyGroupBuilder

// TODO: ctx should be removed when we migrate leverageKeeper and oracleKeeper
ctx *sdk.Context
Expand All @@ -54,6 +59,7 @@ func (b Builder) Keeper(ctx *sdk.Context) Keeper {
bankKeeper: b.bankKeeper,
leverageKeeper: b.leverageKeeper,
oracleKeeper: b.oracleKeeper,
ugov: b.ugov,
ctx: ctx,
}
}
Expand Down
191 changes: 141 additions & 50 deletions x/metoken/keeper/metoken.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package keeper

import (
"errors"
"fmt"
"time"

sdkmath "cosmossdk.io/math"
Expand Down Expand Up @@ -72,6 +73,7 @@ func (k Keeper) setNextInterestClaimTime(nextInterestClaimTime time.Time) {
func (k Keeper) UpdateIndexes(
addIndexes []metoken.Index,
updateIndexes []metoken.Index,
kosegor marked this conversation as resolved.
Show resolved Hide resolved
byEmergencyGroup bool,
) error {
registry := k.GetAllRegisteredIndexes()

Expand All @@ -84,57 +86,86 @@ func (k Keeper) UpdateIndexes(
}
}

if err := k.addIndexes(addIndexes, registeredIndexes, registeredAssets); err != nil {
return err
var errs []error
if byEmergencyGroup {
if len(addIndexes) > 0 {
errs = append(errs, sdkerrors.ErrInvalidRequest.Wrapf("Emergency Group cannot register new indexes"))
}

if updErrs := validateEmergencyIndexUpdate(updateIndexes, registeredIndexes); len(updErrs) > 0 {
errs = append(errs, updErrs...)
}
kosegor marked this conversation as resolved.
Show resolved Hide resolved

if len(errs) > 0 {
return errors.Join(errs...)
}
}

return k.updateIndexes(updateIndexes, registeredIndexes, registeredAssets)
if addErrs := k.addIndexes(addIndexes, registeredIndexes, registeredAssets); len(addErrs) > 0 {
errs = append(errs, addErrs...)
}

if updErrs := k.updateIndexes(updateIndexes, registeredIndexes, registeredAssets); len(updErrs) > 0 {
errs = append(errs, updErrs...)
}

if len(errs) > 0 {
return errors.Join(errs...)
}

return nil
kosegor marked this conversation as resolved.
Show resolved Hide resolved
}

// addIndexes handles addition of the indexes from the request along with their validations.
func (k Keeper) addIndexes(
indexes []metoken.Index,
registeredIndexes map[string]metoken.Index,
registeredAssets map[string]string,
) error {
) []error {
var allErrs []error
for _, index := range indexes {
var indexErrs []error
if _, present := registeredIndexes[index.Denom]; present {
return sdkerrors.ErrInvalidRequest.Wrapf(
"add: index with denom %s already exists",
index.Denom,
allErrs = append(
allErrs, sdkerrors.ErrInvalidRequest.Wrapf(
"add: index with denom %s already exists",
index.Denom,
),
)
}

if exists := k.hasIndexBalance(index.Denom); exists {
allErrs = append(
allErrs, sdkerrors.ErrInvalidRequest.Wrapf(
"can't add index %s - it already exists and is active",
index.Denom,
),
)
}

var errs []error
for _, aa := range index.AcceptedAssets {
if _, present := registeredAssets[aa.Denom]; present {
errs = append(
errs, sdkerrors.ErrInvalidRequest.Wrapf(
indexErrs = append(
indexErrs, sdkerrors.ErrInvalidRequest.Wrapf(
"add: asset %s is already accepted in another index",
aa.Denom,
),
)
}
kosegor marked this conversation as resolved.
Show resolved Hide resolved
}

if len(errs) != 0 {
return errors.Join(errs...)
if errs := k.validateInLeverage(index); len(errs) > 0 {
indexErrs = append(indexErrs, errs...)
}

if err := k.validateInLeverage(index); err != nil {
return err
}

if exists := k.hasIndexBalance(index.Denom); exists {
return sdkerrors.ErrInvalidRequest.Wrapf(
"can't add index %s - it already exists and is active",
index.Denom,
)
if len(indexErrs) > 0 {
allErrs = append(allErrs, indexErrs...)
continue
}

// adding index
if err := k.setRegisteredIndex(index); err != nil {
return err
return []error{err}
}

assetBalances := make([]metoken.AssetBalance, 0)
Expand All @@ -151,10 +182,14 @@ func (k Keeper) addIndexes(
), assetBalances,
),
); err != nil {
return err
return []error{err}
}
}

if len(allErrs) != 0 {
return allErrs
}

return nil
}

Expand All @@ -163,65 +198,74 @@ func (k Keeper) updateIndexes(
indexes []metoken.Index,
registeredIndexes map[string]metoken.Index,
registeredAssets map[string]string,
) error {
) []error {
var allErrs []error
for _, index := range indexes {
var indexErrs []error
kosegor marked this conversation as resolved.
Show resolved Hide resolved
oldIndex, present := registeredIndexes[index.Denom]
if !present {
return sdkerrors.ErrNotFound.Wrapf(
"update: index with denom %s not found",
index.Denom,
allErrs = append(
allErrs, sdkerrors.ErrNotFound.Wrapf(
"update: index with denom %s not found",
index.Denom,
),
)
continue
}

var errs []error
for _, aa := range index.AcceptedAssets {
if indexDenom, present := registeredAssets[aa.Denom]; present && indexDenom != index.Denom {
errs = append(
errs, sdkerrors.ErrInvalidRequest.Wrapf(
indexErrs = append(
indexErrs, sdkerrors.ErrInvalidRequest.Wrapf(
"add: asset %s is already accepted in another index",
aa.Denom,
),
)
}
}

if len(errs) != 0 {
return errors.Join(errs...)
}

if oldIndex.Exponent != index.Exponent {
balances, err := k.IndexBalances(index.Denom)
if err != nil {
return err
return []error{err}
}

if balances.MetokenSupply.IsPositive() {
return sdkerrors.ErrInvalidRequest.Wrapf(
"update: index %s exponent cannot be changed when supply is greater than zero",
index.Denom,
indexErrs = append(
indexErrs, sdkerrors.ErrInvalidRequest.Wrapf(
"update: index %s exponent cannot be changed when supply is greater than zero",
index.Denom,
),
)
}
}

for _, aa := range oldIndex.AcceptedAssets {
if exists := index.HasAcceptedAsset(aa.Denom); !exists {
return sdkerrors.ErrInvalidRequest.Wrapf(
"update: an asset %s cannot be deleted from an index %s",
aa.Denom,
index.Denom,
indexErrs = append(
indexErrs, sdkerrors.ErrInvalidRequest.Wrapf(
"update: an asset %s cannot be deleted from an index %s",
aa.Denom,
index.Denom,
),
)
}
}

if err := k.validateInLeverage(index); err != nil {
return err
if errs := k.validateInLeverage(index); len(errs) > 0 {
indexErrs = append(indexErrs, errs...)
}

if len(indexErrs) > 0 {
allErrs = append(allErrs, indexErrs...)
continue
}

// updating balances if there is a new accepted asset
if len(index.AcceptedAssets) > len(oldIndex.AcceptedAssets) {
balances, err := k.IndexBalances(index.Denom)
if err != nil {
return err
return []error{err}
}

for _, aa := range index.AcceptedAssets {
Expand All @@ -231,27 +275,74 @@ func (k Keeper) updateIndexes(
}

if err := k.setIndexBalances(balances); err != nil {
return err
return []error{err}
}
}

if err := k.setRegisteredIndex(index); err != nil {
return err
return []error{err}
}
}

if len(allErrs) != 0 {
return allErrs
}

return nil
}

func validateEmergencyIndexUpdate(indexes []metoken.Index, registeredIndexes map[string]metoken.Index) []error {
kosegor marked this conversation as resolved.
Show resolved Hide resolved
var errs []error
for _, newIndex := range indexes {
oldIndex, ok := registeredIndexes[newIndex.Denom]
kosegor marked this conversation as resolved.
Show resolved Hide resolved
if !ok {
errs = append(
errs, sdkerrors.ErrNotFound.Wrapf(
"update: index with denom %s not found",
newIndex.Denom,
),
)
continue
}

if newIndex.Exponent != oldIndex.Exponent {
errs = append(errs, errors.New("exponent cannot be changed"))
kosegor marked this conversation as resolved.
Show resolved Hide resolved
}

if !newIndex.Fee.Equal(oldIndex.Fee) {
errs = append(errs, errors.New("fee cannot be changed"))
}

if !newIndex.MaxSupply.Equal(oldIndex.MaxSupply) {
errs = append(errs, errors.New("max_supply cannot be changed"))
}

for _, newAsset := range newIndex.AcceptedAssets {
oldAsset, i := oldIndex.AcceptedAsset(newAsset.Denom)
if i < 0 {
errs = append(errs, fmt.Errorf("new asset %s cannot be added", newAsset.Denom))
continue
}

if !newAsset.ReservePortion.Equal(oldAsset.ReservePortion) {
errs = append(errs, fmt.Errorf("reserve_portion of %s cannot be changed", newAsset.Denom))
}
}
}

return errs
}

// validateInLeverage validate the existence of every accepted asset in x/leverage
func (k Keeper) validateInLeverage(index metoken.Index) error {
func (k Keeper) validateInLeverage(index metoken.Index) []error {
var errs []error
for _, aa := range index.AcceptedAssets {
if _, err := k.leverageKeeper.GetTokenSettings(*k.ctx, aa.Denom); err != nil {
return err
errs = append(errs, err)
}
}

return nil
return errs
}

func ModuleAddr() sdk.AccAddress {
Expand Down
Loading
Loading