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 1 commit
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)
)
9 changes: 8 additions & 1 deletion x/market/internal/keeper/params.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,19 @@ 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)
return
}

// TobinTaxList is a list of tax rates on all spot conversions of the specific Terra into another Terra
// TobinTax will be used for the denoms which are not in the list
func (k Keeper) TobinTaxList(ctx sdk.Context) (res types.TobinTaxList) {
k.paramSpace.Get(ctx, types.ParmamStoreKeyTobinTaxList, &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
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)
tobinTaxList := k.TobinTaxList(ctx)

// Apply highest tobin tax for the denoms in the swap operation
for _, tobinTax := range tobinTaxList {
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 TestTobinTaxListParams(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.TobinTaxList = 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
27 changes: 22 additions & 5 deletions x/market/internal/types/params.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ var (
ParamStoreKeyMinSpread = []byte("minspread")
// Tobin tax
ParmamStoreKeyTobinTax = []byte("tobintax")
yun-yeo marked this conversation as resolved.
Show resolved Hide resolved
// Tobin tax list
ParmamStoreKeyTobinTaxList = []byte("tobintaxlist")
)

// Default parameter values
Expand All @@ -30,16 +32,23 @@ var (
DefaultPoolRecoveryPeriod = core.BlocksPerDay // 14,400
DefaultMinSpread = sdk.NewDecWithPrec(2, 2) // 2%
DefaultTobinTax = sdk.NewDecWithPrec(25, 4) // 0.25%
DefaultTobinTaxList = 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"`
TobinTaxList TobinTaxList `json:"tobin_tax_list" yaml:"tobin_tax_list"`
yun-yeo marked this conversation as resolved.
Show resolved Hide resolved
}

// DefaultParams creates default market module parameters
Expand All @@ -49,6 +58,7 @@ func DefaultParams() Params {
PoolRecoveryPeriod: DefaultPoolRecoveryPeriod,
MinSpread: DefaultMinSpread,
TobinTax: DefaultTobinTax,
TobinTaxList: DefaultTobinTaxList,
}
}

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.TobinTaxList {
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 @@ -79,6 +94,7 @@ func (params *Params) ParamSetPairs() subspace.ParamSetPairs {
{Key: ParamStoreKeyPoolRecoveryPeriod, Value: &params.PoolRecoveryPeriod},
{Key: ParamStoreKeyMinSpread, Value: &params.MinSpread},
{Key: ParmamStoreKeyTobinTax, Value: &params.TobinTax},
{Key: ParmamStoreKeyTobinTaxList, Value: &params.TobinTaxList},
}
}

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)
TobinTaxList: %s
`, params.BasePool, params.PoolRecoveryPeriod, params.MinSpread, params.TobinTax, params.TobinTaxList)
}
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