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

[Bugfix] oracle & market overflow #291

Merged
merged 1 commit into from
Nov 24, 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
29 changes: 14 additions & 15 deletions x/market/alias.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,9 @@ import (

const (
DefaultCodespace = types.DefaultCodespace
CodeInsufficientSwap = types.CodeInsufficientSwap
CodeInsufficientSwap = types.CodeInvalidOfferCoin
CodeNoEffectivePrice = types.CodeNoEffectivePrice
CodeRecursiveSwap = types.CodeRecursiveSwap
CodeInactive = types.CodeInactive
ModuleName = types.ModuleName
StoreKey = types.StoreKey
RouterKey = types.RouterKey
Expand All @@ -28,19 +27,19 @@ const (

var (
// functions aliases
RegisterCodec = types.RegisterCodec
ErrNoEffectivePrice = types.ErrNoEffectivePrice
ErrInsufficientSwapCoins = types.ErrInsufficientSwapCoins
ErrRecursiveSwap = types.ErrRecursiveSwap
NewGenesisState = types.NewGenesisState
DefaultGenesisState = types.DefaultGenesisState
ValidateGenesis = types.ValidateGenesis
NewMsgSwap = types.NewMsgSwap
DefaultParams = types.DefaultParams
NewQuerySwapParams = types.NewQuerySwapParams
NewKeeper = keeper.NewKeeper
ParamKeyTable = keeper.ParamKeyTable
NewQuerier = keeper.NewQuerier
RegisterCodec = types.RegisterCodec
ErrNoEffectivePrice = types.ErrNoEffectivePrice
ErrInvalidOfferCoin = types.ErrInvalidOfferCoin
ErrRecursiveSwap = types.ErrRecursiveSwap
NewGenesisState = types.NewGenesisState
DefaultGenesisState = types.DefaultGenesisState
ValidateGenesis = types.ValidateGenesis
NewMsgSwap = types.NewMsgSwap
DefaultParams = types.DefaultParams
NewQuerySwapParams = types.NewQuerySwapParams
NewKeeper = keeper.NewKeeper
ParamKeyTable = keeper.ParamKeyTable
NewQuerier = keeper.NewQuerier

// variable aliases
ModuleCdc = types.ModuleCdc
Expand Down
4 changes: 4 additions & 0 deletions x/market/internal/keeper/querier.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ func querySwap(ctx sdk.Context, req abci.RequestQuery, keeper Keeper) ([]byte, s
return nil, types.ErrRecursiveSwap(types.DefaultCodespace, params.AskDenom)
}

if params.OfferCoin.Amount.BigInt().BitLen() > 100 {
return nil, types.ErrInvalidOfferCoin(keeper.Codespace(), params.OfferCoin.Amount)
}

swapCoin, spread, err := keeper.ComputeSwap(ctx, params.OfferCoin, params.AskDenom)
if err != nil {
return nil, sdk.ErrInternal(sdk.AppendMsgToErr("Failed to get swapped coin amount", err.Error()))
Expand Down
15 changes: 15 additions & 0 deletions x/market/internal/keeper/querier_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,21 @@ func TestQuerySwap(t *testing.T) {
res, err := querier(input.Ctx, []string{types.QuerySwap}, query)
require.Error(t, err)

// overflow query
overflowAmt, _ := sdk.NewIntFromString("1000000000000000000000000000000000")
overflowOfferCoin := sdk.NewCoin(core.MicroLunaDenom, overflowAmt)
queryParams = types.NewQuerySwapParams(overflowOfferCoin, core.MicroSDRDenom)
bz, err = cdc.MarshalJSON(queryParams)
require.NoError(t, err)

query = abci.RequestQuery{
Path: "",
Data: bz,
}

_, err = querier(input.Ctx, []string{types.QuerySwap}, query)
require.Error(t, err)

// valid query
queryParams = types.NewQuerySwapParams(offerCoin, core.MicroSDRDenom)
bz, err = cdc.MarshalJSON(queryParams)
Expand Down
2 changes: 1 addition & 1 deletion x/market/internal/keeper/swap.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ func (k Keeper) ComputeInternalSwap(ctx sdk.Context, offerCoin sdk.DecCoin, askD

retAmount := offerCoin.Amount.Mul(askRate).Quo(offerRate)
if retAmount.LTE(sdk.ZeroDec()) {
return sdk.DecCoin{}, types.ErrInsufficientSwapCoins(types.DefaultCodespace, offerCoin.Amount.TruncateInt())
return sdk.DecCoin{}, types.ErrInvalidOfferCoin(types.DefaultCodespace, offerCoin.Amount.TruncateInt())
}

return sdk.NewDecCoinFromDec(askDenom, retAmount), nil
Expand Down
9 changes: 4 additions & 5 deletions x/market/internal/types/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,9 @@ type codeType = sdk.CodeType
const (
DefaultCodespace sdk.CodespaceType = "market"

CodeInsufficientSwap codeType = 1
CodeInvalidOfferCoin codeType = 1
CodeNoEffectivePrice codeType = 2
CodeRecursiveSwap codeType = 3
CodeInactive codeType = 4
)

// ----------------------------------------
Expand All @@ -24,9 +23,9 @@ func ErrNoEffectivePrice(codespace sdk.CodespaceType, denom string) sdk.Error {
return sdk.NewError(codespace, CodeNoEffectivePrice, "No price registered with the oracle for asset: "+denom)
}

// ErrInsufficientSwapCoins called when not enough coins are being requested for a swap
func ErrInsufficientSwapCoins(codespace sdk.CodespaceType, rval sdk.Int) sdk.Error {
return sdk.NewError(codespace, CodeInsufficientSwap, "Not enough coins for a swap: "+rval.String())
// ErrInvalidOfferCoin called when not enough or too huge coins are being requested for a swap
func ErrInvalidOfferCoin(codespace sdk.CodespaceType, rval sdk.Int) sdk.Error {
return sdk.NewError(codespace, CodeInvalidOfferCoin, "Invalid offer coin for a swap: "+rval.String())
}

// ErrRecursiveSwap called when Ask and Offer coin denominatioins are equal
Expand Down
4 changes: 2 additions & 2 deletions x/market/internal/types/msgs.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,8 @@ func (msg MsgSwap) ValidateBasic() sdk.Error {
return sdk.ErrInvalidAddress("Invalid address: " + msg.Trader.String())
}

if msg.OfferCoin.Amount.LTE(sdk.ZeroInt()) {
return ErrInsufficientSwapCoins(DefaultCodespace, msg.OfferCoin.Amount)
if msg.OfferCoin.Amount.LTE(sdk.ZeroInt()) || msg.OfferCoin.Amount.BigInt().BitLen() > 100 {
return ErrInvalidOfferCoin(DefaultCodespace, msg.OfferCoin.Amount)
}

if msg.OfferCoin.Denom == msg.AskDenom {
Expand Down
3 changes: 3 additions & 0 deletions x/market/internal/types/msgs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import (
func TestMsgSwap(t *testing.T) {
_, addrs, _, _ := mock.CreateGenAccounts(1, sdk.Coins{})

overflowOfferAmt, _ := sdk.NewIntFromString("100000000000000000000000000000000000000000000000000000000")

tests := []struct {
trader sdk.AccAddress
offerCoin sdk.Coin
Expand All @@ -22,6 +24,7 @@ func TestMsgSwap(t *testing.T) {
{addrs[0], sdk.NewCoin(core.MicroLunaDenom, sdk.OneInt()), core.MicroSDRDenom, true},
{sdk.AccAddress{}, sdk.NewCoin(core.MicroLunaDenom, sdk.OneInt()), core.MicroSDRDenom, false},
{addrs[0], sdk.NewCoin(core.MicroLunaDenom, sdk.ZeroInt()), core.MicroSDRDenom, false},
{addrs[0], sdk.NewCoin(core.MicroLunaDenom, overflowOfferAmt), core.MicroSDRDenom, false},
{addrs[0], sdk.NewCoin(core.MicroLunaDenom, sdk.OneInt()), core.MicroLunaDenom, false},
}

Expand Down
5 changes: 5 additions & 0 deletions x/oracle/internal/types/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,11 @@ func ErrUnknownDenomination(codespace sdk.CodespaceType, denom string) sdk.Error
return sdk.NewError(codespace, CodeUnknownDenom, fmt.Sprintf("The denom is not known: %s", denom))
}

// ErrInvalidExchangeRate called when the rate submitted is not valid
func ErrInvalidExchangeRate(codespace sdk.CodespaceType, rate sdk.Dec) sdk.Error {
return sdk.NewError(codespace, CodeInvalidExchangeRate, fmt.Sprintf("ExchangeRate is invalid: %s", rate.String()))
}

// ErrVerificationFailed called when the given prevote has different hash from the retrieved one
func ErrVerificationFailed(codespace sdk.CodespaceType, hash []byte, retrivedHash []byte) sdk.Error {
return sdk.NewError(codespace, CodeVerificationFailed, fmt.Sprintf("Retrieved hash [%s] differs from prevote hash [%s]", retrivedHash, hash))
Expand Down
5 changes: 5 additions & 0 deletions x/oracle/internal/types/msgs.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,11 @@ func (msg MsgExchangeRateVote) ValidateBasic() sdk.Error {
return sdk.ErrInvalidAddress("Invalid address: " + msg.Feeder.String())
}

// Check overflow bit length
if msg.ExchangeRate.BitLen() > 100+sdk.DecimalPrecisionBits {
return ErrInvalidExchangeRate(DefaultCodespace, msg.ExchangeRate)
}

if len(msg.Salt) > 4 || len(msg.Salt) < 1 {
return ErrInvalidSaltLength(DefaultCodespace, len(msg.Salt))
}
Expand Down
3 changes: 3 additions & 0 deletions x/oracle/internal/types/msgs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ func TestMsgExchangeRatePrevote(t *testing.T) {
func TestMsgExchangeRateVote(t *testing.T) {
_, addrs, _, _ := mock.CreateGenAccounts(1, sdk.Coins{})

overflowExchangeRate, _ := sdk.NewDecFromStr("100000000000000000000000000000000000000000000000000000000")

tests := []struct {
denom string
voter sdk.AccAddress
Expand All @@ -53,6 +55,7 @@ func TestMsgExchangeRateVote(t *testing.T) {
{"", addrs[0], "123", sdk.OneDec(), false},
{core.MicroCNYDenom, addrs[0], "123", sdk.OneDec().MulInt64(core.MicroUnit), true},
{core.MicroCNYDenom, addrs[0], "123", sdk.ZeroDec(), true},
{core.MicroCNYDenom, addrs[0], "123", overflowExchangeRate, false},
{core.MicroCNYDenom, sdk.AccAddress{}, "123", sdk.OneDec().MulInt64(core.MicroUnit), false},
{core.MicroCNYDenom, addrs[0], "", sdk.OneDec().MulInt64(core.MicroUnit), false},
}
Expand Down