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

[Feature] New market params for the high volatility TERRA #300

Merged
merged 3 commits into from
Dec 3, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions types/alias.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ const (
MicroJPYDenom = assets.MicroJPYDenom
MicroEURDenom = assets.MicroEURDenom
MicroGBPDenom = assets.MicroGBPDenom
MicroMNTDenom = assets.MicroMNTDenom
MicroUnit = assets.MicroUnit
BlocksPerMinute = util.BlocksPerMinute
BlocksPerHour = util.BlocksPerHour
Expand Down
1 change: 1 addition & 0 deletions types/assets/assets.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ const (
MicroJPYDenom = "ujpy"
MicroEURDenom = "ueur"
MicroGBPDenom = "ugbp"
MicroMNTDenom = "umnt"

MicroUnit = int64(1e6)
)
21 changes: 11 additions & 10 deletions x/market/alias.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,16 +42,17 @@ var (
NewQuerier = keeper.NewQuerier

// variable aliases
ModuleCdc = types.ModuleCdc
TerraPoolDeltaKey = types.TerraPoolDeltaKey
ParamStoreKeyBasePool = types.ParamStoreKeyBasePool
ParamStoreKeyPoolRecoveryPeriod = types.ParamStoreKeyPoolRecoveryPeriod
ParamStoreKeyMinSpread = types.ParamStoreKeyMinSpread
ParmamStoreKeyTobinTax = types.ParmamStoreKeyTobinTax
DefaultBasePool = types.DefaultBasePool
DefaultPoolRecoveryPeriod = types.DefaultPoolRecoveryPeriod
DefaultMinSpread = types.DefaultMinSpread
DefaultTobinTax = types.DefaultTobinTax
ModuleCdc = types.ModuleCdc
TerraPoolDeltaKey = types.TerraPoolDeltaKey
ParamStoreKeyBasePool = types.ParamStoreKeyBasePool
ParamStoreKeyPoolRecoveryPeriod = types.ParamStoreKeyPoolRecoveryPeriod
ParamStoreKeyMinSpread = types.ParamStoreKeyMinSpread
ParmaStoreKeyTobinTax = types.ParmaStoreKeyTobinTax
ParmaStoreKeyIlliquidTobinTaxList = types.ParmaStoreKeyIlliquidTobinTaxList
DefaultBasePool = types.DefaultBasePool
DefaultPoolRecoveryPeriod = types.DefaultPoolRecoveryPeriod
DefaultMinSpread = types.DefaultMinSpread
DefaultTobinTax = types.DefaultTobinTax
)

type (
Expand Down
11 changes: 9 additions & 2 deletions x/market/internal/keeper/params.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,16 @@ func (k Keeper) PoolRecoveryPeriod(ctx sdk.Context) (res int64) {
return
}

// TobinTax is a tax on all spot conversions of one Terra into another Terra
// TobinTax is a tax rate on all spot conversions of one Terra into another Terra
func (k Keeper) TobinTax(ctx sdk.Context) (res sdk.Dec) {
k.paramSpace.Get(ctx, types.ParmamStoreKeyTobinTax, &res)
k.paramSpace.Get(ctx, types.ParmaStoreKeyTobinTax, &res)
return
}

// IlliquidTobinTaxList is the exceptions that have to pay a higher tobin tax due to illiquidity
// TobinTax will be used for the denoms which are not in the list
func (k Keeper) IlliquidTobinTaxList(ctx sdk.Context) (res types.TobinTaxList) {
k.paramSpace.Get(ctx, types.ParmaStoreKeyIlliquidTobinTaxList, &res)
return
}

Expand Down
12 changes: 12 additions & 0 deletions x/market/internal/keeper/swap.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,18 @@ func (k Keeper) ComputeSwap(ctx sdk.Context, offerCoin sdk.Coin, askDenom string
// Apply only tobin tax without constant product spread
if offerCoin.Denom != core.MicroLunaDenom && askDenom != core.MicroLunaDenom {
spread = k.TobinTax(ctx)
illiquidTobinTaxList := k.IlliquidTobinTaxList(ctx)

// Apply highest tobin tax for the denoms in the swap operation
for _, tobinTax := range illiquidTobinTaxList {
if tobinTax.Denom == offerCoin.Denom ||
tobinTax.Denom == askDenom {
if tobinTax.TaxRate.GT(spread) {
spread = tobinTax.TaxRate
}
}
}

return
}

Expand Down
43 changes: 43 additions & 0 deletions x/market/internal/keeper/swap_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (

sdk "github.com/cosmos/cosmos-sdk/types"
core "github.com/terra-project/core/types"
"github.com/terra-project/core/x/market/internal/types"
)

func TestApplySwapToPool(t *testing.T) {
Expand Down Expand Up @@ -82,3 +83,45 @@ func TestComputeInternalSwap(t *testing.T) {
_, err := input.MarketKeeper.ComputeInternalSwap(input.Ctx, offerCoin, core.MicroLunaDenom)
require.Error(t, err)
}

func TestIlliquidTobinTaxListParams(t *testing.T) {
input := CreateTestInput(t)

// Set Oracle Price
lunaPriceInSDR := sdk.NewDecWithPrec(17, 1)
lunaPriceInMNT := sdk.NewDecWithPrec(7652, 1)
input.OracleKeeper.SetLunaExchangeRate(input.Ctx, core.MicroSDRDenom, lunaPriceInSDR)
input.OracleKeeper.SetLunaExchangeRate(input.Ctx, core.MicroMNTDenom, lunaPriceInMNT)

// Case 1: tobin tax 2% due to umnt denom
params := input.MarketKeeper.GetParams(input.Ctx)
params.TobinTax = sdk.NewDecWithPrec(25, 4)
params.IlliquidTobinTaxList = types.TobinTaxList{
types.TobinTax{
Denom: core.MicroSDRDenom,
TaxRate: sdk.NewDecWithPrec(25, 4),
},
types.TobinTax{
Denom: core.MicroMNTDenom,
TaxRate: sdk.NewDecWithPrec(2, 2),
},
}
input.MarketKeeper.SetParams(input.Ctx, params)

swapAmountInSDR := lunaPriceInSDR.MulInt64(rand.Int63()%10000 + 2).TruncateInt()
offerCoin := sdk.NewCoin(core.MicroSDRDenom, swapAmountInSDR)
_, spread, err := input.MarketKeeper.ComputeSwap(input.Ctx, offerCoin, core.MicroMNTDenom)
require.NoError(t, err)
require.Equal(t, sdk.NewDecWithPrec(2, 2), spread)

// Case 2: tobin tax 5% due to default
params.TobinTax = sdk.NewDecWithPrec(5, 2)
input.MarketKeeper.SetParams(input.Ctx, params)

swapAmountInSDR = lunaPriceInSDR.MulInt64(rand.Int63()%10000 + 2).TruncateInt()
offerCoin = sdk.NewCoin(core.MicroSDRDenom, swapAmountInSDR)
_, spread, err = input.MarketKeeper.ComputeSwap(input.Ctx, offerCoin, core.MicroMNTDenom)
require.NoError(t, err)
require.Equal(t, sdk.NewDecWithPrec(5, 2), spread)

}
2 changes: 2 additions & 0 deletions x/market/internal/types/genesis_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ func TestGenesisValidation(t *testing.T) {

genState.Params.MinSpread = sdk.NewDec(-1)
require.Error(t, ValidateGenesis(genState))

require.True(t, len(genState.Params.String()) != 0)
}

func TestGenesisEqual(t *testing.T) {
Expand Down
47 changes: 32 additions & 15 deletions x/market/internal/types/params.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,34 +21,44 @@ var (
// Min spread
ParamStoreKeyMinSpread = []byte("minspread")
// Tobin tax
ParmamStoreKeyTobinTax = []byte("tobintax")
ParmaStoreKeyTobinTax = []byte("tobintax")
// Illiquid tobin tax list
ParmaStoreKeyIlliquidTobinTaxList = []byte("illiquidtobintaxlist")
)

// Default parameter values
var (
DefaultBasePool = sdk.NewDec(250000 * core.MicroUnit) // 250,000sdr = 250,000,000,000usdr
DefaultPoolRecoveryPeriod = core.BlocksPerDay // 14,400
DefaultMinSpread = sdk.NewDecWithPrec(2, 2) // 2%
DefaultTobinTax = sdk.NewDecWithPrec(25, 4) // 0.25%
DefaultBasePool = sdk.NewDec(250000 * core.MicroUnit) // 250,000sdr = 250,000,000,000usdr
DefaultPoolRecoveryPeriod = core.BlocksPerDay // 14,400
DefaultMinSpread = sdk.NewDecWithPrec(2, 2) // 2%
DefaultTobinTax = sdk.NewDecWithPrec(25, 4) // 0.25%
DefaultIlliquidTobinTaxList = TobinTaxList{
{
Denom: core.MicroMNTDenom,
TaxRate: sdk.NewDecWithPrec(2, 2), // 2%
},
}
)

var _ subspace.ParamSet = &Params{}

// Params market parameters
type Params struct {
PoolRecoveryPeriod int64 `json:"pool_recovery_period" yaml:"pool_recovery_period"`
BasePool sdk.Dec `json:"base_pool" yaml:"base_pool"`
MinSpread sdk.Dec `json:"min_spread" yaml:"min_spread"`
TobinTax sdk.Dec `json:"tobin_tax" yaml:"tobin_tax"`
PoolRecoveryPeriod int64 `json:"pool_recovery_period" yaml:"pool_recovery_period"`
BasePool sdk.Dec `json:"base_pool" yaml:"base_pool"`
MinSpread sdk.Dec `json:"min_spread" yaml:"min_spread"`
TobinTax sdk.Dec `json:"tobin_tax" yaml:"tobin_tax"`
IlliquidTobinTaxList TobinTaxList `json:"illiquid_tobin_tax_list" yaml:"illiquid_tobin_tax_list"`
}

// DefaultParams creates default market module parameters
func DefaultParams() Params {
return Params{
BasePool: DefaultBasePool,
PoolRecoveryPeriod: DefaultPoolRecoveryPeriod,
MinSpread: DefaultMinSpread,
TobinTax: DefaultTobinTax,
BasePool: DefaultBasePool,
PoolRecoveryPeriod: DefaultPoolRecoveryPeriod,
MinSpread: DefaultMinSpread,
TobinTax: DefaultTobinTax,
IlliquidTobinTaxList: DefaultIlliquidTobinTaxList,
}
}

Expand All @@ -66,6 +76,11 @@ func (params Params) Validate() error {
if params.TobinTax.IsNegative() || params.TobinTax.GT(sdk.OneDec()) {
return fmt.Errorf("tobin tax should be a value between [0,1], is %s", params.TobinTax)
}
for _, val := range params.IlliquidTobinTaxList {
if val.TaxRate.IsNegative() || val.TaxRate.GT(sdk.OneDec()) {
return fmt.Errorf("tobin tax should be a value between [0,1], is %s", val)
}
}

return nil
}
Expand All @@ -78,7 +93,8 @@ func (params *Params) ParamSetPairs() subspace.ParamSetPairs {
{Key: ParamStoreKeyBasePool, Value: &params.BasePool},
{Key: ParamStoreKeyPoolRecoveryPeriod, Value: &params.PoolRecoveryPeriod},
{Key: ParamStoreKeyMinSpread, Value: &params.MinSpread},
{Key: ParmamStoreKeyTobinTax, Value: &params.TobinTax},
{Key: ParmaStoreKeyTobinTax, Value: &params.TobinTax},
{Key: ParmaStoreKeyIlliquidTobinTaxList, Value: &params.IlliquidTobinTaxList},
}
}

Expand All @@ -89,5 +105,6 @@ func (params Params) String() string {
PoolRecoveryPeriod: %d
MinSpread: %s
TobinTax: %s
`, params.BasePool, params.PoolRecoveryPeriod, params.MinSpread, params.TobinTax)
IlliquidTobinTaxList: %s
`, params.BasePool, params.PoolRecoveryPeriod, params.MinSpread, params.TobinTax, params.IlliquidTobinTaxList)
}
34 changes: 34 additions & 0 deletions x/market/internal/types/tobin_tax.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package types

import (
"fmt"

sdk "github.com/cosmos/cosmos-sdk/types"
)

// TobinTax - struct to store tobin tax for the specific denom with high volatility
type TobinTax struct {
Denom string `json:"denom" yaml:"denom"`
TaxRate sdk.Dec `json:"tax_rate" yaml:"tax_rate"`
}

// String implements fmt.Stringer interface
func (tt TobinTax) String() string {
return fmt.Sprintf(`TobinTax
Denom: %s,
TaxRate: %s`,
tt.Denom, tt.TaxRate)
}

// TobinTaxList is convience wrapper to handle TobinTax array
type TobinTaxList []TobinTax

// String implements fmt.Stringer interface
func (ttl TobinTaxList) String() (out string) {
out = ""
for _, tt := range ttl {
out += tt.String() + "\n"
}

return
}
5 changes: 2 additions & 3 deletions x/oracle/internal/types/denom.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import (
type DenomList []string

// String implements fmt.Stringer interface
func (dl DenomList) String() (out string) {
strings.Join(dl, "\n")
return
func (dl DenomList) String() string {
return strings.Join(dl, "\n")
}
4 changes: 2 additions & 2 deletions x/oracle/internal/types/vote.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,8 @@ func (pv ExchangeRateVote) getPower(ctx sdk.Context, powerMap map[string]int64)
// String implements fmt.Stringer interface
func (pv ExchangeRateVote) String() string {
return fmt.Sprintf(`ExchangeRateVote
Denom: %s,
Voter: %s,
Denom: %s,
Voter: %s,
ExchangeRate: %s`,
pv.Denom, pv.Voter, pv.ExchangeRate)
}
Expand Down