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/oracle spread #150

Merged
merged 19 commits into from
Jun 4, 2019
Merged
Show file tree
Hide file tree
Changes from 4 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
14 changes: 5 additions & 9 deletions app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,8 @@ func NewTerraApp(logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest,
app.oracleKeeper = oracle.NewKeeper(
app.cdc,
app.keyOracle,
app.distrKeeper,
app.feeCollectionKeeper,
stakingKeeper.GetValidatorSet(),
app.paramsKeeper.Subspace(oracle.DefaultParamspace),
)
Expand Down Expand Up @@ -318,17 +320,11 @@ func (app *TerraApp) BeginBlocker(ctx sdk.Context, req abci.RequestBeginBlock) a
func (app *TerraApp) EndBlocker(ctx sdk.Context, req abci.RequestEndBlock) abci.ResponseEndBlock {
validatorUpdates, tags := staking.EndBlocker(ctx, app.stakingKeeper)

oracleClaims, oracleTags := oracle.EndBlocker(ctx, app.oracleKeeper)
oracleTags := oracle.EndBlocker(ctx, app.oracleKeeper)
tags = append(tags, oracleTags...)
for _, oracleClaim := range oracleClaims {
app.treasuryKeeper.AddClaim(ctx, oracleClaim)
}

budgetClaims, budgetTags := budget.EndBlocker(ctx, app.budgetKeeper)

budgetTags := budget.EndBlocker(ctx, app.budgetKeeper)
tags = append(tags, budgetTags...)
for _, budgetClaim := range budgetClaims {
app.treasuryKeeper.AddClaim(ctx, budgetClaim)
}

treasuryTags := treasury.EndBlocker(ctx, app.treasuryKeeper)
tags = append(tags, treasuryTags...)
Expand Down
2 changes: 1 addition & 1 deletion docs/guide/validators.md
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ You can edit your validator's public description. This info is to identify your
The `--identity` can be used as to verify identity with systems like Keybase or UPort. When using with Keybase `--identity` should be populated with a 16-digit string that is generated with a [keybase.io](https://keybase.io) account. It's a cryptographically secure method of verifying your identity across multiple online networks. The Keybase API allows us to retrieve your Keybase avatar. This is how you can add a logo to your validator profile.

```bash
terracli tx staking edit-validator
terracli tx staking edit-validator \
--moniker="choose a moniker" \
--website="https://terra.money" \
--identity=6A0D65E29A4CBC8E \
Expand Down
32 changes: 2 additions & 30 deletions types/claim.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,54 +6,26 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
)

// ClaimClass is used to categorize type of Claim
type ClaimClass byte

const (
// OracleClaimClass represents oracle claim type
OracleClaimClass ClaimClass = iota
// BudgetClaimClass represents budget claim type
BudgetClaimClass
)

//------------------------------------
//------------------------------------
//------------------------------------

// Claim is an interface that directs its rewards to an attached bank account.
type Claim struct {
Class ClaimClass `json:"class"`
Weight sdk.Int `json:"weight"`
Recipient sdk.AccAddress `json:"recipient"`
}

// NewClaim generates a Claim instance.
func NewClaim(class ClaimClass, weight sdk.Int, recipient sdk.AccAddress) Claim {
func NewClaim(weight sdk.Int, recipient sdk.AccAddress) Claim {
return Claim{
Class: class,
Weight: weight,
Recipient: recipient,
}
}

// ID returns the id of the claim
func (c Claim) ID() string {
return fmt.Sprintf("%d:%s", c.Class, c.Recipient.String())
}

func (c Claim) getClassString() string {
switch c.Class {
case OracleClaimClass:
return "oracle"
case BudgetClaimClass:
return "budget"
}
return "unknown"
}

func (c Claim) String() string {
return fmt.Sprintf(`Claim
Class: %v
Weight: %v
Recipient: %v`, c.getClassString(), c.Weight, c.Recipient)
Recipient: %v`, c.Weight, c.Recipient)
}
15 changes: 14 additions & 1 deletion types/claimpool.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
package types

import "fmt"
import (
"fmt"

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

// ClaimPool is a list of Claims
type ClaimPool []Claim
Expand Down Expand Up @@ -28,6 +32,15 @@ func (cp ClaimPool) Sort() ClaimPool {
return cp
}

// TotalWeight gets the sum of the weights of claims in the claimpool
func (cp ClaimPool) TotalWeight() sdk.Int {
sum := sdk.ZeroInt()
for _, claim := range cp {
sum = sum.Add(claim.Weight)
}
return sum
}

func (cp ClaimPool) String() (out string) {
out = "ClaimPool "
for _, claim := range cp {
Expand Down
4 changes: 2 additions & 2 deletions x/budget/end_blocker.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ func clearsThreshold(votePower, totalPower sdk.Int, threshold sdk.Dec) bool {
}

// EndBlocker is called at the end of every block
func EndBlocker(ctx sdk.Context, k Keeper) (claims types.ClaimPool, resTags sdk.Tags) {
func EndBlocker(ctx sdk.Context, k Keeper) (resTags sdk.Tags) {
params := k.GetParams(ctx)
claims = types.ClaimPool{}
resTags = sdk.EmptyTags()
Expand Down Expand Up @@ -81,7 +81,7 @@ func EndBlocker(ctx sdk.Context, k Keeper) (claims types.ClaimPool, resTags sdk.
return
}

claims = types.ClaimPool{}
claims := types.ClaimPool{}

// iterate programs and weight them
k.IteratePrograms(ctx, true, func(program Program) (stop bool) {
Expand Down
3 changes: 1 addition & 2 deletions x/budget/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ type Keeper struct {
key sdk.StoreKey // Key to our module's store
valset sdk.ValidatorSet // Needed to compute voting power.

mk mint.Keeper // Needed to handle deposits. This module only requires read/writes to Terra balance
mk mint.Keeper // Needed to handle deposits. This module only requires read/writes to Terra balance
paramSpace params.Subspace
}

Expand Down Expand Up @@ -103,7 +103,6 @@ func (k Keeper) IterateVotesWithPrefix(ctx sdk.Context, prefix []byte, handler f
if handler(programID, voterAddr, option) {
break
}

}
}

Expand Down
6 changes: 3 additions & 3 deletions x/market/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ func ErrRecursiveSwap(codespace sdk.CodespaceType, denom string) sdk.Error {
return sdk.NewError(codespace, CodeRecursiveSwap, "Can't swap tokens with the same denomination: "+denom)
}

// ErrExceedsDailySwapLimit called when the coin swap exceeds the daily swap limit
func ErrExceedsDailySwapLimit(codespace sdk.CodespaceType, denom string) sdk.Error {
return sdk.NewError(codespace, CodeExceedsSwapLimit, "Exceeded the daily swap limit for the ask denomination: "+denom)
// ErrExceedsDailySwapLimit called when the coin swap exceeds the daily swap limit for Luna
func ErrExceedsDailySwapLimit(codespace sdk.CodespaceType) sdk.Error {
return sdk.NewError(codespace, CodeExceedsSwapLimit, "Exceeded the daily swap limit for Luna")
}
16 changes: 16 additions & 0 deletions x/market/expected_keeper.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package market

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

// expected oracle keeper
type OracleKeeper interface {
AddSwapFeePool(ctx sdk.Context, fees sdk.Coins)
GetLunaSwapRate(ctx sdk.Context, denom string) (price sdk.Dec, err sdk.Error)
}

// expected mint keeper
type MintKeeper interface {
Mint(ctx sdk.Context, recipient sdk.AccAddress, coin sdk.Coin) (err sdk.Error)
Burn(ctx sdk.Context, payer sdk.AccAddress, coin sdk.Coin) (err sdk.Error)
GetIssuance(ctx sdk.Context, denom string, day sdk.Int) (issuance sdk.Int)
}
53 changes: 13 additions & 40 deletions x/market/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,6 @@ package market
import (
"reflect"

"github.com/terra-project/core/types/assets"
"github.com/terra-project/core/types/util"

"github.com/terra-project/core/x/market/tags"

sdk "github.com/cosmos/cosmos-sdk/types"
Expand All @@ -24,49 +21,30 @@ func NewHandler(k Keeper) sdk.Handler {
}
}

// Returns true if the amount of total coins swapped INTO Luna during a 24 hr window
// (block approximation) exceeds 1% of coinissuance.
func exceedsDailySwapLimit(ctx sdk.Context, k Keeper, swapCoin sdk.Coin, dailyLimit sdk.Dec) bool {
curDay := ctx.BlockHeight() / util.BlocksPerDay

// Start limits on day 2
if curDay != 0 {
curIssuance := k.mk.GetIssuance(ctx, swapCoin.Denom, sdk.NewInt(curDay))
prevIssuance := k.mk.GetIssuance(ctx, swapCoin.Denom, sdk.NewInt(curDay-1))

if curIssuance.GT(prevIssuance) {
dailyDelta := curIssuance.Sub(prevIssuance).Add(swapCoin.Amount)

// If daily inflation is greater than 1%
if dailyDelta.MulRaw(sdk.NewDec(1).Quo(dailyLimit).TruncateInt64()).GT(curIssuance) {
return true
}
}
}

return false
}

// handleMsgSwap handles the logic of a MsgSwap
func handleMsgSwap(ctx sdk.Context, k Keeper, msg MsgSwap) sdk.Result {

params := k.GetParams(ctx)

// Can't swap to the same coin
if msg.OfferCoin.Denom == msg.AskDenom {
return ErrRecursiveSwap(DefaultCodespace, msg.AskDenom).Result()
}

// Compute exchange rates between the ask and offer
swapCoin, swapErr := k.GetSwapCoins(ctx, msg.OfferCoin, msg.AskDenom)
swapCoin, spread, swapErr := k.GetSwapCoins(ctx, msg.OfferCoin, msg.AskDenom, false)
if swapErr != nil {
return swapErr.Result()
}

// We've passed the daily swap limit for Luna. Fail.
// TODO: add safety checks for Terra as well.
if msg.OfferCoin.Denom == assets.MicroLunaDenom && exceedsDailySwapLimit(ctx, k, swapCoin, params.DailySwapLimit) {
return ErrExceedsDailySwapLimit(DefaultCodespace, swapCoin.Denom).Result()
// Charge a spread if applicable; distributed to vote winners in the oracle module
swapFee := sdk.Coin{}
if spread.IsPositive() {
swapFeeAmt := spread.MulInt(swapCoin.Amount).TruncateInt()
if swapFeeAmt.IsPositive() {
swapFee = sdk.NewCoin(swapCoin.Denom, swapFeeAmt)
k.ok.AddSwapFeePool(ctx, sdk.NewCoins(swapFee))

swapCoin = swapCoin.Sub(swapFee)
}
}

// Burn offered coins and subtract from the trader's account
Expand All @@ -75,24 +53,19 @@ func handleMsgSwap(ctx sdk.Context, k Keeper, msg MsgSwap) sdk.Result {
return burnErr.Result()
}

// Record seigniorage if the offered coin is Luna
if msg.OfferCoin.Denom == assets.MicroLunaDenom {
k.mk.AddSeigniorage(ctx, msg.OfferCoin.Amount)
}

// Mint asked coins and credit Trader's account
mintErr := k.mk.Mint(ctx, msg.Trader, swapCoin)
if mintErr != nil {
return mintErr.Result()
}

log := NewLog()
log.append(LogKeySwapCoin, swapCoin.String())
log = log.append(LogKeySwapCoin, swapCoin.String())
log = log.append(LogKeySwapFee, swapFee.String())

return sdk.Result{
Tags: sdk.NewTags(
tags.Offer, msg.OfferCoin.Denom,
tags.Ask, swapCoin.String(),
tags.Trader, msg.Trader.String(),
),
Log: log.String(),
Expand Down
8 changes: 3 additions & 5 deletions x/market/handler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import (
"github.com/terra-project/core/types/assets"
"github.com/terra-project/core/types/util"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

sdk "github.com/cosmos/cosmos-sdk/types"
Expand Down Expand Up @@ -98,7 +97,7 @@ func TestHandlerExceedDailySwapLimit(t *testing.T) {
input := createTestInput(t)
handler := NewHandler(input.marketKeeper)

offerCoin := sdk.NewInt64Coin(assets.MicroSDRDenom, 100)
offerCoin := sdk.NewInt64Coin(assets.MicroSDRDenom, 1000)

// Set oracle price
offerLunaPrice := sdk.NewDec(1)
Expand All @@ -111,14 +110,13 @@ func TestHandlerExceedDailySwapLimit(t *testing.T) {

// Day 1+ ... Set luna issuance, try to oscillate within the limit, and things should be ok
input.ctx = input.ctx.WithBlockHeight(util.BlocksPerWeek)
err := input.mintKeeper.Mint(input.ctx, addrs[0], sdk.NewInt64Coin(assets.MicroLunaDenom, 1000000))
assert.Nil(t, err)
offerCoin = sdk.NewCoin(offerCoin.Denom, sdk.NewInt(4))
msg = NewMsgSwap(addrs[0], offerCoin, assets.MicroLunaDenom)
res = handler(input.ctx, msg)
require.True(t, res.IsOK())

// Day 1+ ... Outside of the limit fails
msg = NewMsgSwap(addrs[0], sdk.NewInt64Coin(assets.MicroLunaDenom, 10005), assets.MicroLunaDenom)
msg = NewMsgSwap(addrs[0], sdk.NewInt64Coin(assets.MicroLunaDenom, 6), assets.MicroLunaDenom)
res = handler(input.ctx, msg)
require.False(t, res.IsOK())

Expand Down
Loading