Skip to content

Commit

Permalink
upd types
Browse files Browse the repository at this point in the history
  • Loading branch information
albertchon committed Dec 15, 2020
1 parent 7288db2 commit 02e28d6
Show file tree
Hide file tree
Showing 7 changed files with 2,045 additions and 4,823 deletions.
2 changes: 0 additions & 2 deletions chain/orders/types/codec.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,5 @@ func RegisterInterfaces(registry codectypes.InterfaceRegistry) {
&MsgSuspendSpotMarket{},
&MsgResumeSpotMarket{},
&MsgCreateSpotOrder{},
&MsgRequestFillSpotOrder{},
&MsgRequestSoftCancelSpotOrder{},
)
}
38 changes: 21 additions & 17 deletions chain/orders/types/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,25 @@ import (
)

var (
ErrOrderInvalid = sdkerrors.Register(ModuleName, 1, "failed to validate order")
ErrOrderNotFound = sdkerrors.Register(ModuleName, 2, "no active order found for the hash")
ErrPairSuspended = sdkerrors.Register(ModuleName, 3, "trade pair suspended")
ErrPairNotFound = sdkerrors.Register(ModuleName, 4, "trade pair not found")
ErrPairExists = sdkerrors.Register(ModuleName, 5, "trade pair exists")
ErrPairMismatch = sdkerrors.Register(ModuleName, 6, "trade pair mismatch")
ErrBadField = sdkerrors.Register(ModuleName, 7, "struct field error")
ErrMarketNotFound = sdkerrors.Register(ModuleName, 8, "derivative market not found")
ErrMarketInvalid = sdkerrors.Register(ModuleName, 9, "failed to validate derivative market")
ErrMarketExists = sdkerrors.Register(ModuleName, 10, "market exists")
ErrMarketSuspended = sdkerrors.Register(ModuleName, 11, "market suspended")
ErrBadUpdateEvent = sdkerrors.Register(ModuleName, 12, "order update event not confirmed")
ErrUpdateSameValue = sdkerrors.Register(ModuleName, 13, "cannot update the record's field with the same value")
ErrOverLeveragedOrder = sdkerrors.Register(ModuleName, 14, "cannot add overlevered order")
ErrSubaccountNotFound = sdkerrors.Register(ModuleName, 15, "subaccount not found")
ErrOrderAlreadyExists = sdkerrors.Register(ModuleName, 16, "order already exists")
ErrInsufficientMargin = sdkerrors.Register(ModuleName, 17, "subaccount has insufficient margin")
ErrOrderInvalid = sdkerrors.Register(ModuleName, 1, "failed to validate order")
ErrOrderNotFound = sdkerrors.Register(ModuleName, 2, "no active order found for the hash")
ErrPairSuspended = sdkerrors.Register(ModuleName, 3, "trade pair suspended")
ErrPairNotFound = sdkerrors.Register(ModuleName, 4, "trade pair not found")
ErrPairExists = sdkerrors.Register(ModuleName, 5, "trade pair exists")
ErrPairMismatch = sdkerrors.Register(ModuleName, 6, "trade pair mismatch")
ErrBadField = sdkerrors.Register(ModuleName, 7, "struct field error")
ErrMarketNotFound = sdkerrors.Register(ModuleName, 8, "derivative market not found")
ErrMarketInvalid = sdkerrors.Register(ModuleName, 9, "failed to validate derivative market")
ErrMarketExists = sdkerrors.Register(ModuleName, 10, "market exists")
ErrMarketSuspended = sdkerrors.Register(ModuleName, 11, "market suspended")
ErrBadUpdateEvent = sdkerrors.Register(ModuleName, 12, "order update event not confirmed")
ErrUpdateSameValue = sdkerrors.Register(ModuleName, 13, "cannot update the record's field with the same value")
ErrOverLeveragedOrder = sdkerrors.Register(ModuleName, 14, "cannot add overlevered order")
ErrSubaccountNotFound = sdkerrors.Register(ModuleName, 15, "subaccount not found")
ErrOrderAlreadyExists = sdkerrors.Register(ModuleName, 16, "order already exists")
ErrInsufficientMargin = sdkerrors.Register(ModuleName, 17, "subaccount has insufficient margin")
ErrMarketExpired = sdkerrors.Register(ModuleName, 18, "market has already expired")
ErrOrderExpired = sdkerrors.Register(ModuleName, 19, "order has already expired")
ErrInsufficientOrderQuantity = sdkerrors.Register(ModuleName, 20, "order quantity invalid")
ErrUnrecognizedOrderType = sdkerrors.Register(ModuleName, 21, "unrecognized order type")
)
4 changes: 4 additions & 0 deletions chain/orders/types/events.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,14 @@ const (
EventTypeFillDerivativeOrder = "fill_derivative_order"
EventTypeHardCancelSpotOrder = "hard_cancel_spot_order"
EventTypeFillSpotOrder = "fill_spot_order"
EventTypeSetPrice = "set_price"

AttributeKeyOrderHash = "order_hash"
AttributeKeyMarketID = "market_id"
AttributeKeySubaccountID = "subaccount_id"
AttributeKeyTradePairHash = "trade_pair_hash"
AttributeKeySignedOrder = "signed_order"
AttributeKeyFilledAmount = "filled_amount"
AttributeKeyPrice = "price"
AttributeKeyTicker = "ticker"
)
228 changes: 101 additions & 127 deletions chain/orders/types/msgs.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ import (
"bytes"
"errors"
"fmt"
"github.com/ethereum/go-ethereum/crypto"
"math/big"
"strings"

"github.com/ethereum/go-ethereum/crypto"
"time"

"github.com/ethereum/go-ethereum/common"

Expand All @@ -29,9 +29,6 @@ var (
_ sdk.Msg = &MsgSuspendSpotMarket{}
_ sdk.Msg = &MsgResumeSpotMarket{}
_ sdk.Msg = &MsgCreateSpotOrder{}
_ sdk.Msg = &MsgRequestFillSpotOrder{}
_ sdk.Msg = &MsgRequestSoftCancelSpotOrder{}
_ sdk.Msg = &MsgExecuteTakerTransaction{}
)

// Route should return the name of the module
Expand All @@ -46,12 +43,15 @@ func (msg MsgCreateSpotOrder) ValidateBasic() error {
return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, msg.Sender)
}

quantity := BigNum(msg.Order.GetTakerAssetAmount()).Int()
if msg.Order == nil {
return sdkerrors.Wrap(sdkerrors.ErrUnknownRequest, "no make order specified")
} else if _, err := msg.Order.ToSignedOrder().ComputeOrderHash(); err != nil {
return sdkerrors.Wrap(sdkerrors.ErrUnknownRequest, fmt.Sprintf("hash check failed: %v", err))
} else if !isValidSignature(msg.Order.Signature) {
return sdkerrors.Wrap(sdkerrors.ErrUnknownRequest, "invalid signature")
} else if quantity == nil || quantity.Cmp(big.NewInt(0)) <= 0 {
return sdkerrors.Wrap(ErrInsufficientOrderQuantity, "insufficient quantity")
}

return nil
Expand Down Expand Up @@ -145,98 +145,6 @@ func (msg MsgCreateDerivativeOrder) GetSigners() []sdk.AccAddress {
return []sdk.AccAddress{sender}
}

// Route should return the name of the module
func (msg MsgRequestFillSpotOrder) Route() string { return RouterKey }

// Type should return the action
func (msg MsgRequestFillSpotOrder) Type() string { return "requestFillSpotOrder" }

// ValidateBasic runs stateless checks on the message
func (msg MsgRequestFillSpotOrder) ValidateBasic() error {
if msg.Sender == "" {
return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, msg.Sender)
}

if msg.TxOrigin == "" {
return sdkerrors.Wrap(ErrBadField, "no txOrigin address specified")
} else if len(msg.SignedTransaction.Salt) == 0 {
return sdkerrors.Wrap(ErrBadField, "no salt specified")
} else if msg.SignedTransaction.SignerAddress == "" {
return sdkerrors.Wrap(ErrBadField, "no signerAddress address specified")
} else if msg.SignedTransaction.Domain.VerifyingContract == "" {
return sdkerrors.Wrap(ErrBadField, "no verifyingContract address specified")
} else if len(msg.SignedTransaction.Domain.ChainId) == 0 {
return sdkerrors.Wrap(ErrBadField, "no chainID specified")
} else if len(msg.SignedTransaction.GasPrice) == 0 {
return sdkerrors.Wrap(ErrBadField, "no gasPrice specified")
} else if len(msg.SignedTransaction.ExpirationTimeSeconds) == 0 {
return sdkerrors.Wrap(ErrBadField, "no expirationTimeSeconds specified")
} else if !isValidSignature(msg.SignedTransaction.Signature) {
return sdkerrors.Wrap(ErrBadField, "invalid transaction signature")
} else if !isValidSignature(msg.ApprovalSignature) {
return sdkerrors.Wrap(ErrBadField, "invalid approval signature")
}

return nil
}

// GetSignBytes encodes the message for signing
func (msg *MsgRequestFillSpotOrder) GetSignBytes() []byte {
return sdk.MustSortJSON(ModuleCdc.MustMarshalJSON(msg))
}

// GetSigners defines whose signature is required
func (msg MsgRequestFillSpotOrder) GetSigners() []sdk.AccAddress {
sender, err := sdk.AccAddressFromBech32(msg.Sender)
if err != nil {
panic(err)
}
return []sdk.AccAddress{sender}
}

// Route should return the name of the module
func (msg MsgRequestSoftCancelSpotOrder) Route() string { return RouterKey }

// Type should return the action
func (msg MsgRequestSoftCancelSpotOrder) Type() string { return "softCancelSpotOrder" }

// ValidateBasic runs stateless checks on the message
func (msg MsgRequestSoftCancelSpotOrder) ValidateBasic() error {
if msg.Sender == "" {
return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, msg.Sender)
}
if msg.TxOrigin == "" {
return sdkerrors.Wrap(ErrBadField, "no txOrigin address specified")
} else if len(msg.SignedTransaction.Salt) == 0 {
return sdkerrors.Wrap(ErrBadField, "no salt specified")
} else if msg.SignedTransaction.SignerAddress == "" {
return sdkerrors.Wrap(ErrBadField, "no signerAddress address specified")
} else if msg.SignedTransaction.Domain.VerifyingContract == "" {
return sdkerrors.Wrap(ErrBadField, "no verifyingContract address specified")
} else if len(msg.SignedTransaction.Domain.ChainId) == 0 {
return sdkerrors.Wrap(ErrBadField, "no chainID specified")
} else if len(msg.SignedTransaction.GasPrice) == 0 {
return sdkerrors.Wrap(ErrBadField, "no gasPrice specified")
} else if !isValidSignature(msg.SignedTransaction.Signature) {
return sdkerrors.Wrap(ErrBadField, "invalid signature")
}
return nil
}

// GetSignBytes encodes the message for signing
func (msg *MsgRequestSoftCancelSpotOrder) GetSignBytes() []byte {
return sdk.MustSortJSON(ModuleCdc.MustMarshalJSON(msg))
}

// GetSigners defines whose signature is required
func (msg MsgRequestSoftCancelSpotOrder) GetSigners() []sdk.AccAddress {
sender, err := sdk.AccAddressFromBech32(msg.Sender)
if err != nil {
panic(err)
}
return []sdk.AccAddress{sender}
}

// Route should return the name of the module
func (msg MsgRegisterSpotMarket) Route() string { return RouterKey }

Expand Down Expand Up @@ -460,31 +368,6 @@ func (msg MsgResumeSpotMarket) GetSigners() []sdk.AccAddress {
return []sdk.AccAddress{sender}
}

// Route should return the name of the module
func (msg MsgExecuteTakerTransaction) Route() string { return RouterKey }

// Type should return the action
func (msg MsgExecuteTakerTransaction) Type() string { return "executeTakerTransaction" }

// ValidateBasic runs stateless checks on the message
func (msg MsgExecuteTakerTransaction) ValidateBasic() error {
// TODO : Add basic vaidation
return nil
}

func (msg *MsgExecuteTakerTransaction) GetSignBytes() []byte {
return sdk.MustSortJSON(ModuleCdc.MustMarshalJSON(msg))
}

// GetSigners defines whose signature is required
func (msg MsgExecuteTakerTransaction) GetSigners() []sdk.AccAddress {
sender, err := sdk.AccAddressFromBech32(msg.Sender)
if err != nil {
panic(err)
}
return []sdk.AccAddress{sender}
}

// SafeSignedOrder is a special signed order structure
// for including in Msgs, because it consists of primitive types.
// Avoid using raw *big.Int in Msgs.
Expand Down Expand Up @@ -547,8 +430,99 @@ func (m *BaseOrder) ToSignedOrder() *zeroex.SignedOrder {
return o
}

func ComputeSubaccountID(makerAddress string, takerFee string) (subaccountID common.Hash) {
subaccountID = crypto.Keccak256Hash(
func (order *Order) DoesValidationPass(isLong bool, market *DerivativeMarket, currBlockTime time.Time) error {
err := order.ComputeAndSetOrderType()
if err != nil {
return err
}
orderExpirationTime := BigNum(order.GetOrder().GetExpirationTimeSeconds()).Int()
blockTime := big.NewInt(currBlockTime.Unix())

if orderExpirationTime.Cmp(blockTime) <= 0 {
return sdkerrors.Wrapf(ErrOrderExpired, "order expiration %s <= block time %s", orderExpirationTime.String(), blockTime.String())
}
margin := BigNum(order.Order.GetMakerFee()).Int()
contractPriceMarginRequirement := order.ComputeContractPriceMarginRequirement(market)
if margin.Cmp(contractPriceMarginRequirement) < 0 {
return sdkerrors.Wrapf(ErrOverLeveragedOrder, "margin %s < contractPriceMarginRequirement %s", margin.String(), contractPriceMarginRequirement.String())
}

indexPriceMarginRequirement := order.ComputeIndexPriceMarginRequirement(isLong, market)
indexPrice := BigNum(market.GetIndexPrice()).Int()

if isLong && indexPrice.Cmp(indexPriceMarginRequirement) < 0 {
return sdkerrors.Wrapf(ErrOverLeveragedOrder, "indexPrice %s <= indexPriceReq %s", market.GetIndexPrice(), order.IndexPriceRequirement)
} else if !isLong && indexPrice.Cmp(indexPriceMarginRequirement) > 0 {
return sdkerrors.Wrapf(ErrOverLeveragedOrder, "indexPrice %s >= indexPriceReq %s", market.GetIndexPrice(), order.IndexPriceRequirement)
}
return nil
}

func (order *Order) ComputeAndSetOrderType() error {
orderTypeNumber := new(big.Int).SetBytes(common.FromHex(order.GetOrder().GetMakerFeeAssetData())[:common.HashLength]).Uint64()
if orderTypeNumber != 0 && orderTypeNumber != 5 {
return sdkerrors.Wrapf(ErrUnrecognizedOrderType, "Cannot recognize MakerFeeAssetData of %s", order.GetOrder().GetMakerFeeAssetData())
}
order.OrderType = orderTypeNumber
return nil
}

func (order *Order) ComputeIndexPriceMarginRequirement(isLong bool, market *DerivativeMarket) *big.Int {
price := BigNum(order.Order.GetMakerAssetAmount()).Int()
quantity := BigNum(order.Order.GetTakerAssetAmount()).Int()
margin := BigNum(order.Order.GetMakerFee()).Int()
pq := new(big.Int).Mul(price, quantity)
alphaQuantity := ScalePermyriad(quantity, BigNum(market.InitialMarginRatio).Int())
num := new(big.Int)
denom := new(big.Int)

if isLong {
num = num.Sub(margin, pq)
denom = denom.Sub(alphaQuantity, quantity)
} else {
num = num.Add(margin, pq)
denom = denom.Add(alphaQuantity, quantity)
}

indexPriceReq := new(big.Int).Div(num, denom)
order.IndexPriceRequirement = indexPriceReq.String()
return indexPriceReq
}

// quantity * initialMarginRatio * price
func (order *Order) ComputeContractPriceMarginRequirement(market *DerivativeMarket) *big.Int {
price := BigNum(order.Order.GetMakerAssetAmount()).Int()
quantity := BigNum(order.Order.GetTakerAssetAmount()).Int()
alphaQuantity := ScalePermyriad(quantity, BigNum(market.InitialMarginRatio).Int())
return new(big.Int).Mul(alphaQuantity, price)
}

// orderMarginHold = 1.0015 * margin * (remainingQuantity) / order.quantity
func (o *Order) ComputeOrderMarginHold(remainingQuantity, makerTxFeePermyriad *big.Int) (orderMarginHold *big.Int) {
margin := BigNum(o.GetOrder().GetMakerFee()).Int()
scaledMargin := IncrementByScaledPermyriad(margin, makerTxFeePermyriad)
originalQuantity := BigNum(o.GetOrder().GetTakerAssetAmount()).Int()

// TODO: filledAmount should always be zero with TEC since there will be no UnknownOrderHash
numerator := new(big.Int).Mul(scaledMargin, remainingQuantity)
orderMarginHold = new(big.Int).Div(numerator, originalQuantity)
return orderMarginHold
}

// return amount * (1 + permyriad/10000) = (amount + amount * permyriad/10000)
func IncrementByScaledPermyriad(amount, permyriad *big.Int) *big.Int {
return new(big.Int).Add(amount, ScalePermyriad(amount, permyriad))
}

// return (amount * permyriad) / 10000
func ScalePermyriad(amount, permyriad *big.Int) *big.Int {
PERMYRIAD_BASE := BigNum("10000").Int()
scaleFactor := new(big.Int).Mul(amount, permyriad)
return new(big.Int).Div(scaleFactor, PERMYRIAD_BASE)
}

func ComputeSubaccountID(makerAddress string, takerFee string) common.Hash {
subaccountID := crypto.Keccak256Hash(
common.HexToAddress(makerAddress).Bytes(),
common.LeftPadBytes(BigNum(takerFee).Int().Bytes(), 32),
)
Expand All @@ -557,7 +531,7 @@ func ComputeSubaccountID(makerAddress string, takerFee string) (subaccountID com
}

// GetDirectionMarketAndSubaccountID
func (m *BaseOrder) GetDirectionMarketAndSubaccountID() (isLong bool, marketID string, subaccountID common.Hash) {
func (m *BaseOrder) GetDirectionMarketAndSubaccountID() (isLong bool, marketID common.Hash, subaccountID common.Hash) {
mData, tData := common.FromHex(m.GetMakerAssetData()), common.FromHex(m.GetTakerAssetData())

if len(mData) > common.HashLength {
Expand All @@ -570,10 +544,10 @@ func (m *BaseOrder) GetDirectionMarketAndSubaccountID() (isLong bool, marketID s

if bytes.Equal(tData, common.Hash{}.Bytes()) {
isLong = true
marketID = common.Bytes2Hex(mData)
marketID = common.BytesToHash(mData)
} else {
isLong = false
marketID = common.Bytes2Hex(tData)
marketID = common.BytesToHash(tData)
}
subaccountID = ComputeSubaccountID(m.GetMakerAddress(), m.GetTakerFee())

Expand Down
Loading

0 comments on commit 02e28d6

Please sign in to comment.