Skip to content

Commit

Permalink
Merge pull request #3459 from vegaprotocol/feature/new-transaction-api-2
Browse files Browse the repository at this point in the history
Add validation for a couple of commands
  • Loading branch information
jeremyletang committed May 6, 2021
2 parents 9eba60d + 9b664ec commit 98fb950
Show file tree
Hide file tree
Showing 13 changed files with 898 additions and 75 deletions.
20 changes: 12 additions & 8 deletions commands/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,18 @@ import (
)

var (
ErrIsRequired = errors.New("is required")
ErrMustBePositive = errors.New("must be positive")
ErrMustBePositiveOrZero = errors.New("must be positive or zero")
ErrMustBeNegative = errors.New("must be negative")
ErrMustBeNegativeOrZero = errors.New("must be negative or zero")
ErrIsNotValid = errors.New("is not a valid value")
ErrIsNotSupported = errors.New("is not supported")
ErrIsUnauthorised = errors.New("is unauthorised")
ErrIsRequired = errors.New("is required")
ErrMustBePositive = errors.New("must be positive")
ErrMustBePositiveOrZero = errors.New("must be positive or zero")
ErrMustBeNegative = errors.New("must be negative")
ErrMustBeNegativeOrZero = errors.New("must be negative or zero")
ErrIsNotValid = errors.New("is not a valid value")
ErrIsNotSupported = errors.New("is not supported")
ErrIsUnauthorised = errors.New("is unauthorised")
ErrCannotAmendToGFA = errors.New("cannot amend to time in force GFA")
ErrCannotAmendToGFN = errors.New("cannot amend to time in force GFN")
ErrNonGTTOrderWithExpiry = errors.New("non GTT order with expiry")
ErrGTTOrderWithNoExpiry = errors.New("GTT order without expiry")
)

type Errors map[string]error
Expand Down
145 changes: 145 additions & 0 deletions commands/liquidity_provision_submission.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
package commands

import (
"errors"
"fmt"
"strconv"

types "code.vegaprotocol.io/vega/proto"
commandspb "code.vegaprotocol.io/vega/proto/commands/v1"
)

var (
ErrOrderInShapeWithoutReference = errors.New("order in shape without reference")
ErrOrderInShapeWithoutProportion = errors.New("order in shape without a proportion")
ErrOrderInBuySideShapeWithBestAskPrice = errors.New("order in buy side shape with best ask price reference")
ErrOrderInBuySideShapeOffsetSup0 = errors.New("order in buy side shape offset must be <= 0")
ErrOrderInBuySideShapeOffsetSupEq0 = errors.New("order in buy side shape offset must be < 0")
ErrOrderInSellSideShapeOffsetInf0 = errors.New("order in sell shape offset must be >= 0")
ErrOrderInSellSideShapeWithBestBidPrice = errors.New("order in sell side shape with best bid price reference")
ErrOrderInSellSideShapeOffsetInfEq0 = errors.New("order in sell shape offset must be > 0")
)

func CheckLiquidityProvisionSubmission(cmd *commandspb.LiquidityProvisionSubmission) error {
return checkLiquidityProvisionSubmission(cmd).ErrorOrNil()
}

func checkLiquidityProvisionSubmission(cmd *commandspb.LiquidityProvisionSubmission) Errors {
var errs = NewErrors()

if len(cmd.MarketId) <= 0 {
errs.AddForProperty(
"liquidity_provision_submission.market_id",
ErrIsRequired,
)
}

if len(cmd.Fee) <= 0 {
errs.AddForProperty(
"liquidity_provision_submission.fee",
ErrIsRequired,
)
} else {
if fee, err := strconv.ParseFloat(cmd.Fee, 64); err != nil {
errs.AddForProperty(
"liquidity_provision_submission.fee",
ErrIsNotValid,
)
} else if fee < 0 {
errs.AddForProperty(
"liquidity_provision_submission.fee",
ErrMustBePositive,
)
}

}

errs.Merge(checkLiquidityProvisionShape(
cmd.Buys, types.Side_SIDE_BUY,
))
errs.Merge(checkLiquidityProvisionShape(
cmd.Sells, types.Side_SIDE_SELL,
))

return errs
}

func checkLiquidityProvisionShape(
sh []*types.LiquidityOrder, side types.Side,
) Errors {
var (
errs = NewErrors()
shapeSideField = "liquidity_provision_submission.buys"
)
if side == types.Side_SIDE_SELL {
shapeSideField = "liquidity_provision_submission.sells"
}

if len(sh) <= 0 {
errs.AddForProperty(shapeSideField, errors.New("empty shape"))
return errs

}

for idx, lo := range sh {
if lo.Reference == types.PeggedReference_PEGGED_REFERENCE_UNSPECIFIED {
errs.AddForProperty(
fmt.Sprintf("%v[%d].reference", shapeSideField, idx),
ErrOrderInShapeWithoutReference,
)
}
if lo.Proportion == 0 {
errs.AddForProperty(
fmt.Sprintf("%v[%d].proportion", shapeSideField, idx),
ErrOrderInShapeWithoutProportion,
)
}

if side == types.Side_SIDE_BUY {
switch lo.Reference {
case types.PeggedReference_PEGGED_REFERENCE_BEST_ASK:
errs.AddForProperty(
fmt.Sprintf("%v[%d].reference", shapeSideField, idx),
ErrOrderInBuySideShapeWithBestAskPrice,
)
case types.PeggedReference_PEGGED_REFERENCE_BEST_BID:
if lo.Offset > 0 {
errs.AddForProperty(
fmt.Sprintf("%v[%d].offset", shapeSideField, idx),
ErrOrderInBuySideShapeOffsetSup0,
)
}
case types.PeggedReference_PEGGED_REFERENCE_MID:
if lo.Offset >= 0 {
errs.AddForProperty(
fmt.Sprintf("%v[%d].offset", shapeSideField, idx),
ErrOrderInBuySideShapeOffsetSupEq0,
)
}
}
} else {
switch lo.Reference {
case types.PeggedReference_PEGGED_REFERENCE_BEST_ASK:
if lo.Offset < 0 {
errs.AddForProperty(
fmt.Sprintf("%v[%d].offset", shapeSideField, idx),
ErrOrderInSellSideShapeOffsetInf0,
)
}
case types.PeggedReference_PEGGED_REFERENCE_BEST_BID:
errs.AddForProperty(
fmt.Sprintf("%v[%d].offset", shapeSideField, idx),
ErrOrderInSellSideShapeWithBestBidPrice,
)
case types.PeggedReference_PEGGED_REFERENCE_MID:
if lo.Offset <= 0 {
errs.AddForProperty(
fmt.Sprintf("%v[%d].offset", shapeSideField, idx),
ErrOrderInSellSideShapeOffsetInfEq0,
)
}
}
}
}
return errs
}
170 changes: 170 additions & 0 deletions commands/liquidity_provision_submission_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
package commands_test

import (
"testing"

"code.vegaprotocol.io/vega/commands"
types "code.vegaprotocol.io/vega/proto"
commandspb "code.vegaprotocol.io/vega/proto/commands/v1"

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

func TestLiquidityProvisionSubmission(t *testing.T) {
var cases = []struct {
lp commandspb.LiquidityProvisionSubmission
errString string
}{
{
lp: commandspb.LiquidityProvisionSubmission{
CommitmentAmount: 100,
Fee: "abcd",
MarketId: "okmarketid",
Sells: []*types.LiquidityOrder{
{Reference: types.PeggedReference_PEGGED_REFERENCE_BEST_ASK, Offset: 10, Proportion: 1},
},
Buys: []*types.LiquidityOrder{
{Reference: types.PeggedReference_PEGGED_REFERENCE_BEST_BID, Offset: -10, Proportion: 1},
},
},
errString: "liquidity_provision_submission.fee(is not a valid value)",
},
{
lp: commandspb.LiquidityProvisionSubmission{
CommitmentAmount: 100,
Fee: "-1",
MarketId: "okmarketid",
Sells: []*types.LiquidityOrder{
{Reference: types.PeggedReference_PEGGED_REFERENCE_BEST_ASK, Offset: 10, Proportion: 1},
},
Buys: []*types.LiquidityOrder{
{Reference: types.PeggedReference_PEGGED_REFERENCE_BEST_BID, Offset: -10, Proportion: 1},
},
},
errString: "liquidity_provision_submission.fee(must be positive)",
},
{
lp: commandspb.LiquidityProvisionSubmission{
CommitmentAmount: 100,
Fee: "0.1",
Sells: []*types.LiquidityOrder{
{Reference: types.PeggedReference_PEGGED_REFERENCE_BEST_ASK, Offset: 10, Proportion: 1},
},
Buys: []*types.LiquidityOrder{
{Reference: types.PeggedReference_PEGGED_REFERENCE_BEST_BID, Offset: -10, Proportion: 1},
},
},
errString: "liquidity_provision_submission.market_id(is required)",
},
{
lp: commandspb.LiquidityProvisionSubmission{
CommitmentAmount: 100,
Fee: "0.1",
MarketId: "okmarketid",
Sells: []*types.LiquidityOrder{
{Reference: types.PeggedReference_PEGGED_REFERENCE_BEST_ASK, Offset: 10},
},
Buys: []*types.LiquidityOrder{
{Reference: types.PeggedReference_PEGGED_REFERENCE_BEST_BID, Offset: -10, Proportion: 1},
},
},
errString: "liquidity_provision_submission.sells[0].proportion(order in shape without a proportion)",
},
{
lp: commandspb.LiquidityProvisionSubmission{
CommitmentAmount: 100,
Fee: "0.1",
MarketId: "okmarketid",
Sells: []*types.LiquidityOrder{
{Reference: types.PeggedReference_PEGGED_REFERENCE_BEST_ASK, Offset: 10, Proportion: 1},
},
Buys: []*types.LiquidityOrder{
{Reference: types.PeggedReference_PEGGED_REFERENCE_BEST_BID, Offset: -10},
},
},
errString: "liquidity_provision_submission.buys[0].proportion(order in shape without a proportion)",
},
{
lp: commandspb.LiquidityProvisionSubmission{
CommitmentAmount: 100,
Fee: "0.1",
MarketId: "okmarketid",
Sells: []*types.LiquidityOrder{
{Reference: types.PeggedReference_PEGGED_REFERENCE_BEST_ASK, Proportion: 1}, // no offset is ok
},
Buys: []*types.LiquidityOrder{
{Reference: types.PeggedReference_PEGGED_REFERENCE_BEST_BID, Proportion: 1}, // no offset is ok
},
},
},
{
lp: commandspb.LiquidityProvisionSubmission{
CommitmentAmount: 100,
Fee: "0.1",
MarketId: "okmarketid",
Sells: []*types.LiquidityOrder{
{Reference: types.PeggedReference_PEGGED_REFERENCE_BEST_ASK, Offset: 10, Proportion: 1},
},
Buys: []*types.LiquidityOrder{},
},
errString: "liquidity_provision_submission.buys(empty shape)",
},
{
lp: commandspb.LiquidityProvisionSubmission{
CommitmentAmount: 100,
Fee: "0.1",
MarketId: "okmarketid",
Sells: []*types.LiquidityOrder{},
Buys: []*types.LiquidityOrder{
{Reference: types.PeggedReference_PEGGED_REFERENCE_BEST_BID, Offset: -10, Proportion: 1},
},
},
errString: "liquidity_provision_submission.sells(empty shape)",
},
{
lp: commandspb.LiquidityProvisionSubmission{
CommitmentAmount: 100,
Fee: "0.1",
MarketId: "okmarketid",
Sells: []*types.LiquidityOrder{
{Reference: types.PeggedReference_PEGGED_REFERENCE_BEST_BID, Offset: 10, Proportion: 1},
},
Buys: []*types.LiquidityOrder{
{Reference: types.PeggedReference_PEGGED_REFERENCE_BEST_ASK, Offset: -10, Proportion: 1},
},
},
errString: "liquidity_provision_submission.buys[0].reference(order in buy side shape with best ask price reference), liquidity_provision_submission.sells[0].offset(order in sell side shape with best bid price reference)",
},
{
lp: commandspb.LiquidityProvisionSubmission{
CommitmentAmount: 100,
Fee: "0.1",
MarketId: "okmarketid",
Sells: []*types.LiquidityOrder{
{Reference: types.PeggedReference_PEGGED_REFERENCE_MID, Offset: 0, Proportion: 1},
{Reference: types.PeggedReference_PEGGED_REFERENCE_BEST_BID, Offset: 0, Proportion: 1},
{Reference: types.PeggedReference_PEGGED_REFERENCE_BEST_ASK, Offset: -10, Proportion: 1},
},
Buys: []*types.LiquidityOrder{
{Reference: types.PeggedReference_PEGGED_REFERENCE_MID, Offset: 0, Proportion: 1},
},
},
errString: "liquidity_provision_submission.buys[0].offset(order in buy side shape offset must be < 0), liquidity_provision_submission.sells[0].offset(order in sell shape offset must be > 0), liquidity_provision_submission.sells[1].offset(order in sell side shape with best bid price reference), liquidity_provision_submission.sells[2].offset(order in sell shape offset must be >= 0)",
},
{
lp: commandspb.LiquidityProvisionSubmission{},
errString: "liquidity_provision_submission.buys(empty shape), liquidity_provision_submission.fee(is required), liquidity_provision_submission.market_id(is required), liquidity_provision_submission.sells(empty shape)",
},
}

for _, c := range cases {
err := commands.CheckLiquidityProvisionSubmission(&c.lp)
if len(c.errString) <= 0 {
assert.NoError(t, err)
continue
}

assert.Error(t, err)
assert.EqualError(t, err, c.errString)
}
}

0 comments on commit 98fb950

Please sign in to comment.