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

Reduce the maximum supply cap by a percentage determined by governance #315

Open
wants to merge 21 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions client/docs/swagger-ui/swagger.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -55119,6 +55119,12 @@ definitions:
min_stability_spread:
type: string
format: byte
max_supply_coin:
type: string
format: byte
percentage_supply_max_descending:
type: string
format: byte
description: Params defines the parameters for the market module.
terra.market.v1beta1.QueryParamsResponse:
type: object
Expand Down
2 changes: 1 addition & 1 deletion contrib/terra-operator/entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
DATADIR="${DATADIR:-/terra/.terra/data}"
MONIKER="${MONIKER:-docker-node}"
ENABLE_LCD="${ENABLE_LCD:-true}"
MINIMUM_GAS_PRICES=${MINIMUM_GAS_PRICES-0.01133uluna,0.15uusd,0.104938usdr,169.77ukrw,428.571umnt,0.125ueur,0.98ucny,16.37ujpy,0.11ugbp,10.88uinr,0.19ucad,0.14uchf,0.19uaud,0.2usgd,4.62uthb,1.25usek,1.25unok,0.9udkk,2180.0uidr,7.6uphp,1.17uhkd}
MINIMUM_GAS_PRICES=${MINIMUM_GAS_PRICES-0.01133uluna,0.15uusd,0.104938usdr,169.77ukrw,428.571umnt,0.125ueur,0.98ucny,16.37ujpy,0.11ugbp,10.88uinr,0.19ucad,0.14uchf,0.19uaud,0.2usgd,4.62uthb,1.25usek,1.25unok,0.9udkk,2180.0uidr,7.6uphp,1.17uhkd,0.01uivcs}
SNAPSHOT_NAME="${SNAPSHOT_NAME}"
SNAPSHOT_BASE_URL="${SNAPSHOT_BASE_URL:-https://getsfo.quicksync.io}"

Expand Down
10 changes: 10 additions & 0 deletions proto/terra/market/v1beta1/market.proto
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,14 @@ message Params {
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec",
(gogoproto.nullable) = false
];
bytes max_supply_coin = 4 [
(gogoproto.moretags) = "yaml:\"max_supply_coin\"",
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Coin",
(gogoproto.nullable) = false
];
bytes percentage_supply_max_descending = 5 [
(gogoproto.moretags) = "yaml:\"percentage_supply_max_descending\"",
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec",
(gogoproto.nullable) = false
];
}
25 changes: 25 additions & 0 deletions x/market/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,31 @@ func (k Keeper) SetTerraPoolDelta(ctx sdk.Context, delta sdk.Dec) {
store.Set(types.TerraPoolDeltaKey, bz)
}

// GetTerraPoolDelta returns the gap between the TerraPool and the TerraBasePool
func (k Keeper) GetSupplyMaxDescending(ctx sdk.Context, key []byte) sdk.Int {
store := ctx.KVStore(k.storeKey)
bz := store.Get(key)
if bz == nil {
return sdk.ZeroInt()
}

dp := sdk.IntProto{}
k.cdc.MustUnmarshal(bz, &dp)
return dp.Int
}

// SetTerraPoolDelta updates TerraPoolDelta which is gap between the TerraPool and the BasePool
func (k Keeper) SetSupplyMaxDescending(ctx sdk.Context, key []byte, delta sdk.Int) {
store := ctx.KVStore(k.storeKey)
bz := k.cdc.MustMarshal(&sdk.IntProto{Int: delta})
store.Set(key, bz)
}

func (k Keeper) HasSupplyMaxDescending(ctx sdk.Context, key []byte) bool {
store := ctx.KVStore(k.storeKey)
return store.Has(key)
}

// ReplenishPools replenishes each pool(Terra,Luna) to BasePool
func (k Keeper) ReplenishPools(ctx sdk.Context) {
poolDelta := k.GetTerraPoolDelta(ctx)
Expand Down
54 changes: 54 additions & 0 deletions x/market/keeper/msg_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (

"github.com/classic-terra/core/v2/x/market/types"
oracletypes "github.com/classic-terra/core/v2/x/oracle/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
)

type msgServer struct {
Expand Down Expand Up @@ -67,6 +68,10 @@ func (k msgServer) handleSwapRequest(ctx sdk.Context,
return nil, err
}

errSup := k.ValidateSupplyMaximum(ctx, sdk.NewDecCoin(swapDecCoin.Denom, swapDecCoin.Amount.TruncateInt()))
if errSup != nil {
return nil, errSup
}
// Charge a spread if applicable; the spread is burned
var feeDecCoin sdk.DecCoin
if spread.IsPositive() {
Expand Down Expand Up @@ -97,6 +102,20 @@ func (k msgServer) handleSwapRequest(ctx sdk.Context,
return nil, err
}

for _, offerCoin := range offerCoins {
amountP := sdk.NewDec(offerCoin.Amount.Int64()).Mul(k.PercentageSupplyMaxDescending(ctx))
supplyMaxDescending := k.GetSupplyMaxDescending(ctx, []byte("SupplyMaxDescending"+offerCoin.Denom))
if !k.HasSupplyMaxDescending(ctx, []byte("SupplyMaxDescending"+offerCoin.Denom)) {
ok, amount := k.isExists(ctx, offerCoin.Denom, k.GetMaxSupplyCoin(ctx))
if ok {
supplyMaxDescending = amount
} else {
return nil, sdkerrors.Wrap(types.ErrZeroSwapCoin, "Need to declare the maximum limit of supply "+offerCoin.Denom)
}
}
k.SetSupplyMaxDescending(ctx, []byte("SupplyMaxDescending"+offerCoin.Denom), supplyMaxDescending.Sub(amountP.TruncateInt()))

}
// Mint asked coins and credit Trader's account
swapCoin, decimalCoin := swapDecCoin.TruncateDecimal()

Expand Down Expand Up @@ -150,3 +169,38 @@ func (k msgServer) handleSwapRequest(ctx sdk.Context,
SwapFee: feeCoin,
}, nil
}

func (k Keeper) ValidateSupplyMaximum(ctx sdk.Context, coin sdk.DecCoin) error {
ok, amount := k.isExists(ctx, coin.Denom, k.GetMaxSupplyCoin(ctx))

totalSupply := k.BankKeeper.GetSupply(ctx, coin.Denom)
if ok {
if totalSupply.Amount.Add(coin.Amount.TruncateInt()).GT(amount) {
return sdkerrors.Wrap(types.ErrZeroSwapCoin, "The value to be minted exceeded the maximum supply value "+amount.String()+coin.Denom)
}
} else {
return sdkerrors.Wrap(types.ErrZeroSwapCoin, "maximum supply not configured for currency "+coin.Denom)
}

return nil
}

func (k Keeper) isExists(ctx sdk.Context, demom string, coins sdk.Coins) (result bool, amount sdk.Int) {
result = false
for _, coin := range coins {
if coin.Denom == demom {
amount = coin.Amount
if !k.HasSupplyMaxDescending(ctx, []byte("SupplyMaxDescending"+demom)) {
k.SetSupplyMaxDescending(ctx, []byte("SupplyMaxDescending"+demom), coin.Amount)
} else {
supplyMaxDescending := k.GetSupplyMaxDescending(ctx, []byte("SupplyMaxDescending"+demom))
if coin.Amount.GT(supplyMaxDescending) {
amount = supplyMaxDescending
}
}
result = true
break
}
}
return result, amount
}
14 changes: 14 additions & 0 deletions x/market/keeper/params.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,20 @@ func (k Keeper) PoolRecoveryPeriod(ctx sdk.Context) (res uint64) {
return
}

func (k Keeper) GetMaxSupplyCoin(ctx sdk.Context) (res sdk.Coins) {
k.paramSpace.Get(ctx, types.KeyMaxSupplyCoin, &res)
return
}

func (k Keeper) SetMaxSupplyCoin(ctx sdk.Context, maxSupplyCoin sdk.Coins) {
k.paramSpace.Set(ctx, types.KeyMaxSupplyCoin, maxSupplyCoin)
}

func (k Keeper) PercentageSupplyMaxDescending(ctx sdk.Context) (res sdk.Dec) {
k.paramSpace.Get(ctx, types.KeyPercentageSupplyMaxDescending, &res)
return
}

// GetParams returns the total set of market parameters.
func (k Keeper) GetParams(ctx sdk.Context) (params types.Params) {
k.paramSpace.GetParamSet(ctx, &params)
Expand Down
2 changes: 1 addition & 1 deletion x/market/keeper/swap.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@ func (k Keeper) ComputeSwap(ctx sdk.Context, offerCoin sdk.Coin, askDenom string
if offerCoin.Denom == askDenom {
return sdk.DecCoin{}, sdk.ZeroDec(), sdkerrors.Wrap(types.ErrRecursiveSwap, askDenom)
}

// Swap offer coin to base denom for simplicity of swap process
baseOfferDecCoin, err := k.ComputeInternalSwap(ctx, sdk.NewDecCoinFromCoin(offerCoin), core.MicroSDRDenom)
if err != nil {
Expand Down Expand Up @@ -180,5 +179,6 @@ func (k Keeper) simulateSwap(ctx sdk.Context, offerCoin sdk.Coin, askDenom strin
}

retCoin, _ := swapCoin.TruncateDecimal()

return retCoin, nil
}
8 changes: 5 additions & 3 deletions x/market/legacy/v04/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,11 @@ const (
type (
// Params market parameters
Params struct {
BasePool sdk.Dec `json:"base_pool" yaml:"base_pool"`
PoolRecoveryPeriod int64 `json:"pool_recovery_period" yaml:"pool_recovery_period"`
MinStabilitySpread sdk.Dec `json:"min_spread" yaml:"min_spread"`
BasePool sdk.Dec `json:"base_pool" yaml:"base_pool"`
PoolRecoveryPeriod int64 `json:"pool_recovery_period" yaml:"pool_recovery_period"`
MinStabilitySpread sdk.Dec `json:"min_spread" yaml:"min_spread"`
MaxSupplyCoin sdk.Coins `json:"max_supply_coin" yaml:"max_supply_coin"`
PercentageSupplyMaxDescending sdk.Dec `json:"percentage_supply_max_descending" yaml:"percentage_supply_max_descending"`
}

// GenesisState is the struct representation of the export genesis
Expand Down
8 changes: 5 additions & 3 deletions x/market/legacy/v05/migrate.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,11 @@ func Migrate(
return &v05market.GenesisState{
TerraPoolDelta: sdk.ZeroDec(),
Params: v05market.Params{
BasePool: marketGenState.Params.BasePool,
PoolRecoveryPeriod: uint64(marketGenState.Params.PoolRecoveryPeriod),
MinStabilitySpread: marketGenState.Params.MinStabilitySpread,
BasePool: marketGenState.Params.BasePool,
PoolRecoveryPeriod: uint64(marketGenState.Params.PoolRecoveryPeriod),
MinStabilitySpread: marketGenState.Params.MinStabilitySpread,
MaxSupplyCoin: marketGenState.Params.MaxSupplyCoin,
PercentageSupplyMaxDescending: marketGenState.Params.PercentageSupplyMaxDescending,
},
}
}
128 changes: 119 additions & 9 deletions x/market/legacy/v05/migrate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import (

func TestMigrate(t *testing.T) {
sdk.GetConfig().SetBech32PrefixForAccount(core.Bech32PrefixAccAddr, core.Bech32PrefixAccPub)

encodingConfig := app.MakeEncodingConfig()
clientCtx := client.Context{}.
WithInterfaceRegistry(encodingConfig.InterfaceRegistry).
Expand All @@ -31,7 +30,31 @@ func TestMigrate(t *testing.T) {
Params: v04market.Params{
BasePool: sdk.NewDec(1000000),
PoolRecoveryPeriod: int64(10000),
MinStabilitySpread: sdk.NewDecWithPrec(2, 2),
MinStabilitySpread: sdk.NewDecWithPrec(2, 2), // ATTENTION: The list of modes must be in alphabetical order, otherwise an error occurs in validateMaxSupplyCoin => !v.IsValid()
MaxSupplyCoin: sdk.Coins{
{Denom: "uaud", Amount: sdk.NewInt(500000000000)},
{Denom: "ucad", Amount: sdk.NewInt(500000000000)},
{Denom: "uchf", Amount: sdk.NewInt(500000000000)},
{Denom: "ucny", Amount: sdk.NewInt(500000000000)},
{Denom: "udkk", Amount: sdk.NewInt(500000000000)},
{Denom: "ueur", Amount: sdk.NewInt(500000000000)},
{Denom: "ugbp", Amount: sdk.NewInt(500000000000)},
{Denom: "uhkd", Amount: sdk.NewInt(500000000000)},
{Denom: "uidr", Amount: sdk.NewInt(500000000000)},
{Denom: "uinr", Amount: sdk.NewInt(500000000000)},
{Denom: "ujpy", Amount: sdk.NewInt(500000000000)},
{Denom: "ukrw", Amount: sdk.NewInt(500000000000)},
{Denom: "uluna", Amount: sdk.NewInt(1000000000000)},
{Denom: "umnt", Amount: sdk.NewInt(500000000000)},
{Denom: "unok", Amount: sdk.NewInt(500000000000)},
{Denom: "uphp", Amount: sdk.NewInt(500000000000)},
{Denom: "usdr", Amount: sdk.NewInt(500000000000)},
{Denom: "usek", Amount: sdk.NewInt(500000000000)},
{Denom: "usgd", Amount: sdk.NewInt(500000000000)},
{Denom: "uthb", Amount: sdk.NewInt(500000000000)},
{Denom: "uusd", Amount: sdk.NewInt(500000000000)},
},
PercentageSupplyMaxDescending: sdk.NewDecWithPrec(30, 2), // 30%
},
}

Expand All @@ -50,13 +73,100 @@ func TestMigrate(t *testing.T) {
// Make sure about:
// - BasePool to Mint & Burn pool
expected := `{
"params": {
"base_pool": "1000000.000000000000000000",
"min_stability_spread": "0.020000000000000000",
"pool_recovery_period": "10000"
},
"terra_pool_delta": "0.000000000000000000"
}`
"params": {
"base_pool": "1000000.000000000000000000",
"min_stability_spread": "0.020000000000000000",
"pool_recovery_period": "10000",
"max_supply_coin": [
{
"denom": "uaud",
"amount": "500000000000"
},
{
"denom": "ucad",
"amount": "500000000000"
},
{
"denom": "uchf",
"amount": "500000000000"
},
{
"denom": "ucny",
"amount": "500000000000"
},
{
"denom": "udkk",
"amount": "500000000000"
},
{
"denom": "ueur",
"amount": "500000000000"
},
{
"denom": "ugbp",
"amount": "500000000000"
},
{
"denom": "uhkd",
"amount": "500000000000"
},
{
"denom": "uidr",
"amount": "500000000000"
},
{
"denom": "uinr",
"amount": "500000000000"
},
{
"denom": "ujpy",
"amount": "500000000000"
},
{
"denom": "ukrw",
"amount": "500000000000"
},
{
"denom": "uluna",
"amount": "1000000000000"
},
{
"denom": "umnt",
"amount": "500000000000"
},
{
"denom": "unok",
"amount": "500000000000"
},
{
"denom": "uphp",
"amount": "500000000000"
},
{
"denom": "usdr",
"amount": "500000000000"
},
{
"denom": "usek",
"amount": "500000000000"
},
{
"denom": "usgd",
"amount": "500000000000"
},
{
"denom": "uthb",
"amount": "500000000000"
},
{
"denom": "uusd",
"amount": "500000000000"
}
],
"percentage_supply_max_descending": "0.300000000000000000"
},
"terra_pool_delta": "0.000000000000000000"
}`

assert.JSONEq(t, expected, string(indentedBz))
}
2 changes: 1 addition & 1 deletion x/market/types/expected_keepers.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ type BankKeeper interface {
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
SendCoinsFromAccountToModule(ctx sdk.Context, senderAddr sdk.AccAddress, recipientModule string, amt sdk.Coins) error

GetSupply(ctx sdk.Context, denom string) sdk.Coin
BurnCoins(ctx sdk.Context, name string, amt sdk.Coins) error
MintCoins(ctx sdk.Context, name string, amt sdk.Coins) error

Expand Down
Loading