Skip to content

Commit

Permalink
Merge pull request #19 from InjectiveLabs/dev
Browse files Browse the repository at this point in the history
Dev
  • Loading branch information
albertchon authored Dec 28, 2021
2 parents 334ce1d + 57771d5 commit 890f453
Show file tree
Hide file tree
Showing 12 changed files with 5,023 additions and 1,336 deletions.
2 changes: 2 additions & 0 deletions chain/exchange/types/codec.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ func RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) {
cdc.RegisterConcrete(&MsgExternalTransfer{}, "exchange/MsgExternalTransfer", nil)
cdc.RegisterConcrete(&MsgIncreasePositionMargin{}, "exchange/MsgIncreasePositionMargin", nil)
cdc.RegisterConcrete(&MsgLiquidatePosition{}, "exchange/MsgLiquidatePosition", nil)
cdc.RegisterConcrete(&MsgBatchUpdateOrders{}, "exchange/MsgBatchUpdateOrders", nil)

cdc.RegisterConcrete(&ExchangeEnableProposal{}, "exchange/ExchangeEnableProposal", nil)
cdc.RegisterConcrete(&BatchExchangeModificationProposal{}, "exchange/BatchExchangeModificationProposal", nil)
Expand Down Expand Up @@ -66,6 +67,7 @@ func RegisterInterfaces(registry types.InterfaceRegistry) {
&MsgExternalTransfer{},
&MsgIncreasePositionMargin{},
&MsgLiquidatePosition{},
&MsgBatchUpdateOrders{},
)

registry.RegisterImplementations(
Expand Down
64 changes: 47 additions & 17 deletions chain/exchange/types/common_utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import (
"bytes"
"math/big"
"reflect"
"regexp"
"strings"

sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/ethereum/go-ethereum/common"
Expand Down Expand Up @@ -85,29 +87,35 @@ func StringInSlice(a string, list *[]string) bool {
}

func IsValidSubaccountID(subaccountID string) (*common.Address, bool) {
if len(subaccountID) != 66 {
if !IsHexHash(subaccountID) {
return nil, false
}
subaccountIdBytes := common.FromHex(subaccountID)

if len(subaccountIdBytes) != common.HashLength {
return nil, false
}
addressBytes := subaccountIdBytes[:common.AddressLength]
if !common.IsHexAddress(common.Bytes2Hex(addressBytes)) {
return nil, false
}
address := common.BytesToAddress(addressBytes)
return &address, true
}

func IsValidOrderHash(orderHash string) bool {
if len(orderHash) != 66 {
return IsHexHash(orderHash)
}

// IsHexHash verifies whether a string can represent a valid hex-encoded hash or not.
func IsHexHash(s string) bool {
if !isHexString(s) {
return false
}

orderHashBytes := common.FromHex(orderHash)
return len(orderHashBytes) == common.HashLength
if strings.HasPrefix(s, "0x") {
return len(s) == 2*common.HashLength+2
}

return len(s) == 2*common.HashLength
}

func isHexString(str string) bool {
isMatched, _ := regexp.MatchString("^(0x)?[0-9a-fA-F]+$", str)
return isMatched
}

func BreachesMinimumTickSize(value sdk.Dec, minTickSize sdk.Dec) bool {
Expand Down Expand Up @@ -172,23 +180,45 @@ func DecBytesToDec(bz []byte) sdk.Dec {
}

func HasDuplicates(slice []string) bool {
seen := make(map[string]bool)
seen := make(map[string]struct{})
for _, item := range slice {
if seen[item] {
if _, ok := seen[item]; ok {
return true
}
seen[item] = true
seen[item] = struct{}{}
}
return false
}

func HasDuplicatesHexHash(slice []string) bool {
seen := make(map[common.Hash]struct{})
for _, item := range slice {
if _, ok := seen[common.HexToHash(item)]; ok {
return true
}
seen[common.HexToHash(item)] = struct{}{}
}
return false
}

func HasDuplicatesCoin(slice []sdk.Coin) bool {
seen := make(map[string]bool)
seen := make(map[string]struct{})
for _, item := range slice {
if _, ok := seen[item.Denom]; ok {
return true
}
seen[item.Denom] = struct{}{}
}
return false
}

func HasDuplicatesOrder(slice []*OrderData) bool {
seen := make(map[string]struct{})
for _, item := range slice {
if seen[item.Denom] {
if _, ok := seen[item.OrderHash]; ok {
return true
}
seen[item.Denom] = true
seen[item.OrderHash] = struct{}{}
}
return false
}
2 changes: 2 additions & 0 deletions chain/exchange/types/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,4 +61,6 @@ var (
ErrInvalidFeeDiscountSchedule = sdkerrors.Register(ModuleName, 54, "Invalid fee discount schedule")
ErrInvalidReduceOnlyPosition = sdkerrors.Register(ModuleName, 55, "Invalid position to reduce")
ErrTradingRewardCampaignDistributionError = sdkerrors.Register(ModuleName, 56, "Unknown error happened for campaign distributions")
ErrInvalidTradingRewardsPointsUpdate = sdkerrors.Register(ModuleName, 57, "Invalid trading reward points update")
ErrInvalidBatchMsgUpdate = sdkerrors.Register(ModuleName, 58, "Invalid batch msg update")
)
624 changes: 366 additions & 258 deletions chain/exchange/types/exchange.pb.go

Large diffs are not rendered by default.

14 changes: 9 additions & 5 deletions chain/exchange/types/key.go
Original file line number Diff line number Diff line change
Expand Up @@ -222,19 +222,23 @@ func GetLimitOrderByPriceKeyPrefix(marketID common.Hash, isBuy bool, price sdk.D
}

func GetSpotLimitOrderIndexPrefix(marketID common.Hash, isBuy bool, subaccountID common.Hash) []byte {
return append(SpotLimitOrdersIndexPrefix, getLimitOrderIndexSubaccountPrefix(marketID, isBuy, subaccountID)...)
return append(SpotLimitOrdersIndexPrefix, GetLimitOrderIndexSubaccountPrefix(marketID, isBuy, subaccountID)...)
}

func GetDerivativeLimitOrderIndexPrefix(marketID common.Hash, isBuy bool, subaccountID common.Hash) []byte {
return append(DerivativeLimitOrdersIndexPrefix, getLimitOrderIndexSubaccountPrefix(marketID, isBuy, subaccountID)...)
return append(DerivativeLimitOrdersIndexPrefix, GetLimitOrderIndexSubaccountPrefix(marketID, isBuy, subaccountID)...)
}

func GetLimitOrderIndexKey(marketID common.Hash, isBuy bool, subaccountID, orderHash common.Hash) []byte {
return append(getLimitOrderIndexSubaccountPrefix(marketID, isBuy, subaccountID), orderHash.Bytes()...)
return append(GetLimitOrderIndexSubaccountPrefix(marketID, isBuy, subaccountID), orderHash.Bytes()...)
}

// prefix containing marketID + isBuy + subaccountID
func getLimitOrderIndexSubaccountPrefix(marketID common.Hash, isBuy bool, subaccountID common.Hash) []byte {
func GetTransientLimitOrderIndexIteratorPrefix(marketID common.Hash, isBuy bool, subaccountID common.Hash) []byte {
return append(SpotLimitOrdersIndexPrefix, GetLimitOrderIndexSubaccountPrefix(marketID, isBuy, subaccountID)...)
}

// GetLimitOrderIndexSubaccountPrefix returns a prefix containing marketID + isBuy + subaccountID
func GetLimitOrderIndexSubaccountPrefix(marketID common.Hash, isBuy bool, subaccountID common.Hash) []byte {
return append(MarketDirectionPrefix(marketID, isBuy), subaccountID.Bytes()...)
}

Expand Down
140 changes: 135 additions & 5 deletions chain/exchange/types/msgs.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (

sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/ethereum/go-ethereum/common"
)

const RouterKey = ModuleName
Expand All @@ -29,10 +30,11 @@ var (
_ sdk.Msg = &MsgInstantSpotMarketLaunch{}
_ sdk.Msg = &MsgInstantPerpetualMarketLaunch{}
_ sdk.Msg = &MsgInstantExpiryFuturesMarketLaunch{}
_ sdk.Msg = &MsgBatchUpdateOrders{}
)

func (o *SpotOrder) ValidateBasic(senderAddr sdk.AccAddress) error {
if o.MarketId == "" {
if !IsHexHash(o.MarketId) {
return sdkerrors.Wrap(ErrMarketInvalid, o.MarketId)
}
switch o.OrderType {
Expand Down Expand Up @@ -73,7 +75,7 @@ func (o *OrderInfo) ValidateBasic(senderAddr sdk.AccAddress) error {
}

func (o *DerivativeOrder) ValidateBasic(senderAddr sdk.AccAddress) error {
if o.MarketId == "" {
if !IsHexHash(o.MarketId) {
return sdkerrors.Wrap(ErrMarketInvalid, o.MarketId)
}
switch o.OrderType {
Expand All @@ -99,7 +101,7 @@ func (o *DerivativeOrder) ValidateBasic(senderAddr sdk.AccAddress) error {
}

func (o *OrderData) ValidateBasic(senderAddr sdk.AccAddress) error {
if o.MarketId == "" {
if !IsHexHash(o.MarketId) {
return sdkerrors.Wrap(ErrMarketInvalid, o.MarketId)
}

Expand Down Expand Up @@ -876,9 +878,10 @@ func (msg *MsgIncreasePositionMargin) ValidateBasic() error {
return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, msg.Sender)
}

if msg.MarketId == "" {
if !IsHexHash(msg.MarketId) {
return sdkerrors.Wrap(ErrMarketInvalid, msg.MarketId)
}

if !msg.Amount.IsPositive() {
return sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, msg.Amount.String())
}
Expand Down Expand Up @@ -926,7 +929,7 @@ func (msg *MsgLiquidatePosition) ValidateBasic() error {
return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, msg.Sender)
}

if msg.MarketId == "" {
if !IsHexHash(msg.MarketId) {
return sdkerrors.Wrap(ErrMarketInvalid, msg.MarketId)
}

Expand Down Expand Up @@ -955,3 +958,130 @@ func (msg *MsgLiquidatePosition) GetSigners() []sdk.AccAddress {
}
return []sdk.AccAddress{sender}
}

// Route implements the sdk.Msg interface. It should return the name of the module
func (msg MsgBatchUpdateOrders) Route() string { return RouterKey }

// Type implements the sdk.Msg interface. It should return the action.
func (msg MsgBatchUpdateOrders) Type() string { return "batchUpdateOrders" }

// ValidateBasic implements the sdk.Msg interface. It runs stateless checks on the message
func (msg MsgBatchUpdateOrders) ValidateBasic() error {
sender, err := sdk.AccAddressFromBech32(msg.Sender)
if err != nil {
return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, msg.Sender)
}

hasCancelAllMarketId := len(msg.SpotMarketIdsToCancelAll) > 0 || len(msg.DerivativeMarketIdsToCancelAll) > 0
hasSubaccountIdForCancelAll := msg.SubaccountId != ""

if hasCancelAllMarketId && !hasSubaccountIdForCancelAll {
return sdkerrors.Wrap(ErrInvalidBatchMsgUpdate, "msg contains cancel all marketIDs but no subaccountID")
}

if hasSubaccountIdForCancelAll && !hasCancelAllMarketId {
return sdkerrors.Wrap(ErrInvalidBatchMsgUpdate, "msg contains subaccountID but no cancel all marketIDs")
}

if hasSubaccountIdForCancelAll {
subaccountAddress, ok := IsValidSubaccountID(msg.SubaccountId)
if !ok {
return sdkerrors.Wrap(ErrBadSubaccountID, msg.SubaccountId)
}
if !bytes.Equal(subaccountAddress.Bytes(), sender.Bytes()) {
return sdkerrors.Wrap(ErrBadSubaccountID, msg.Sender)
}

hasDuplicateSpotMarketIds := HasDuplicatesHexHash(msg.SpotMarketIdsToCancelAll)
if hasDuplicateSpotMarketIds {
return sdkerrors.Wrap(ErrInvalidBatchMsgUpdate, "msg contains duplicate cancel all spot market ids")
}

hasDuplicateDerivativesMarketIds := HasDuplicatesHexHash(msg.DerivativeMarketIdsToCancelAll)
if hasDuplicateDerivativesMarketIds {
return sdkerrors.Wrap(ErrInvalidBatchMsgUpdate, "msg contains duplicate cancel all derivative market ids")
}
}

hasDuplicateSpotOrderToCancel := HasDuplicatesOrder(msg.SpotOrdersToCancel)
if hasDuplicateSpotOrderToCancel {
return sdkerrors.Wrap(ErrInvalidBatchMsgUpdate, "msg contains duplicate spot order to cancel")
}

hasDuplicateDerivativeOrderToCancel := HasDuplicatesOrder(msg.DerivativeOrdersToCancel)
if hasDuplicateDerivativeOrderToCancel {
return sdkerrors.Wrap(ErrInvalidBatchMsgUpdate, "msg contains duplicate derivative order to cancel")
}

if len(msg.SpotMarketIdsToCancelAll) > 0 && len(msg.SpotOrdersToCancel) > 0 {
seen := make(map[common.Hash]struct{})
for _, marketID := range msg.SpotMarketIdsToCancelAll {
if !IsHexHash(marketID) {
return sdkerrors.Wrap(ErrMarketInvalid, marketID)
}
seen[common.HexToHash(marketID)] = struct{}{}
}

for idx := range msg.SpotOrdersToCancel {
if _, ok := seen[common.HexToHash(msg.SpotOrdersToCancel[idx].MarketId)]; ok {
return sdkerrors.Wrap(ErrInvalidBatchMsgUpdate, "msg contains order to cancel in a spot market that is also in cancel all")
}
}
}

if len(msg.DerivativeMarketIdsToCancelAll) > 0 && len(msg.DerivativeOrdersToCancel) > 0 {
seen := make(map[common.Hash]struct{})
for _, marketID := range msg.DerivativeMarketIdsToCancelAll {
if !IsHexHash(marketID) {
return sdkerrors.Wrap(ErrMarketInvalid, marketID)
}
seen[common.HexToHash(marketID)] = struct{}{}
}

for idx := range msg.DerivativeOrdersToCancel {
if _, ok := seen[common.HexToHash(msg.DerivativeOrdersToCancel[idx].MarketId)]; ok {
return sdkerrors.Wrap(ErrInvalidBatchMsgUpdate, "msg contains order to cancel in a derivative market that is also in cancel all")
}
}
}

for idx := range msg.SpotOrdersToCancel {
if err := msg.SpotOrdersToCancel[idx].ValidateBasic(sender); err != nil {
return err
}
}

for idx := range msg.DerivativeOrdersToCancel {
if err := msg.DerivativeOrdersToCancel[idx].ValidateBasic(sender); err != nil {
return err
}
}

for idx := range msg.SpotOrdersToCreate {
if err := msg.SpotOrdersToCreate[idx].ValidateBasic(sender); err != nil {
return err
}
}

for idx := range msg.DerivativeOrdersToCreate {
if err := msg.DerivativeOrdersToCreate[idx].ValidateBasic(sender); err != nil {
return err
}
}

return nil
}

// GetSignBytes implements the sdk.Msg interface. It encodes the message for signing
func (msg *MsgBatchUpdateOrders) GetSignBytes() []byte {
return sdk.MustSortJSON(ModuleCdc.MustMarshalJSON(msg))
}

// GetSigners implements the sdk.Msg interface. It defines whose signature is required
func (msg MsgBatchUpdateOrders) GetSigners() []sdk.AccAddress {
sender, err := sdk.AccAddressFromBech32(msg.Sender)
if err != nil {
panic(err)
}
return []sdk.AccAddress{sender}
}
Loading

0 comments on commit 890f453

Please sign in to comment.