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

trader view precompile #181

Open
wants to merge 14 commits into
base: isolated-margin
Choose a base branch
from
Prev Previous commit
Next Next commit
add position cap check in juror
  • Loading branch information
0xshinobii committed Mar 18, 2024
commit 85df6994eaa3da919b171e39db6b815e42ba0aa9
12 changes: 12 additions & 0 deletions precompile/contracts/bibliophile/amm.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ const (
ISOLATED_TRADE_MARGIN_FRACTION_SLOT int64 = 30
ISOLATED_LIQUIDATION_MARGIN_FRACTION_SLOT int64 = 31
ACCOUNT_PREFERENCES_SLOT int64 = 33
MAX_POSITION_CAP_SLOT int64 = 34
)

// AMM State
Expand Down Expand Up @@ -212,6 +213,17 @@ func getRequiredMarginForQuote(stateDB contract.StateDB, market common.Address,
return hu.Div1e6(hu.Mul(quote, marginFraction))
}

func getMaxPositionCap(stateDB contract.StateDB, market common.Address) *big.Int {
return stateDB.GetState(market, common.BigToHash(big.NewInt(MAX_POSITION_CAP_SLOT))).Big()
}

func getPositionCap(stateDB contract.StateDB, market int64, trader *common.Address) *big.Int {
marketAddress := GetMarketAddressFromMarketID(market, stateDB)
maxPositionCap := getMaxPositionCap(stateDB, marketAddress)
traderMarginFraction := getTraderMarginFraction(stateDB, marketAddress, trader)
return hu.Div1e6(hu.Mul(maxPositionCap, traderMarginFraction))
}

// Utils

func getPendingFundingPayment(stateDB contract.StateDB, market common.Address, trader *common.Address) *big.Int {
Expand Down
10 changes: 10 additions & 0 deletions precompile/contracts/bibliophile/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ type BibliophileClient interface {
GetBlockPlaced(orderHash [32]byte) *big.Int
GetOrderFilledAmount(orderHash [32]byte) *big.Int
GetOrderStatus(orderHash [32]byte) int64
GetPrecompileVersion(precompileAddress common.Address) *big.Int

// IOC Order
IOC_GetBlockPlaced(orderHash [32]byte) *big.Int
Expand All @@ -51,6 +52,7 @@ type BibliophileClient interface {
GetPriceMultiplier(market common.Address) *big.Int
GetUpperAndLowerBoundForMarket(marketId int64) (*big.Int, *big.Int)
GetAcceptableBoundsForLiquidation(marketId int64) (*big.Int, *big.Int)
GetPositionCap(marketId int64, trader common.Address) *big.Int

GetTimeStamp() uint64
GetNotionalPositionAndMargin(trader common.Address, includeFundingPayments bool, mode uint8, upgradeVersion hu.UpgradeVersion) (*big.Int, *big.Int)
Expand Down Expand Up @@ -243,3 +245,11 @@ func (b *bibliophileClient) GetRequiredMargin(baseAsset *big.Int, price *big.Int
func (b *bibliophileClient) HasReferrer(trader common.Address) bool {
return HasReferrer(b.accessibleState.GetStateDB(), trader)
}

func (b *bibliophileClient) GetPositionCap(marketId int64, trader common.Address) *big.Int {
return getPositionCap(b.accessibleState.GetStateDB(), marketId, &trader)
}

func (b *bibliophileClient) GetPrecompileVersion(precompileAddress common.Address) *big.Int {
return getPrecompileVersion(b.accessibleState.GetStateDB(), precompileAddress)
}
6 changes: 6 additions & 0 deletions precompile/contracts/bibliophile/limit_order_book.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ const (
REDUCE_ONLY_AMOUNT_SLOT int64 = 2
LONG_OPEN_ORDERS_SLOT int64 = 4
SHORT_OPEN_ORDERS_SLOT int64 = 5
PRECOMPILE_VERSION_SLOT int64 = 8
)

func getOrderFilledAmount(stateDB contract.StateDB, orderHash [32]byte) *big.Int {
Expand Down Expand Up @@ -53,3 +54,8 @@ func getBlockPlaced(stateDB contract.StateDB, orderHash [32]byte) *big.Int {
orderInfo := orderInfoMappingStorageSlot(orderHash)
return new(big.Int).SetBytes(stateDB.GetState(common.HexToAddress(LIMIT_ORDERBOOK_GENESIS_ADDRESS), common.BigToHash(orderInfo)).Bytes())
}

func getPrecompileVersion(stateDB contract.StateDB, precompileAddress common.Address) *big.Int {
slot := new(big.Int).SetBytes(crypto.Keccak256(append(common.LeftPadBytes(precompileAddress.Bytes(), 32), common.LeftPadBytes(big.NewInt(PRECOMPILE_VERSION_SLOT).Bytes(), 32)...)))
return stateDB.GetState(common.HexToAddress(LIMIT_ORDERBOOK_GENESIS_ADDRESS), common.BigToHash(slot)).Big()
}
11 changes: 10 additions & 1 deletion precompile/contracts/juror/ioc_orders.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,8 @@ func ValidatePlaceIOCorder(bibliophile b.BibliophileClient, inputStruct *Validat
}

// this check is sort of redundant because either ways user can circumvent this by placing several reduceOnly order in a single tx/block
posSize := bibliophile.GetSize(ammAddress, &trader)
if order.ReduceOnly {
posSize := bibliophile.GetSize(ammAddress, &trader)
// a reduce only order should reduce position
if !reducesPosition(posSize, order.BaseAssetQuantity) {
response.Err = ErrReduceOnlyBaseAssetQuantityInvalid.Error()
Expand All @@ -91,6 +91,15 @@ func ValidatePlaceIOCorder(bibliophile b.BibliophileClient, inputStruct *Validat
response.Err = ErrPricePrecision.Error()
return
}

if bibliophile.GetPrecompileVersion(common.HexToAddress(SelfAddress)).Cmp(big.NewInt(1)) >= 0 {
posCap := bibliophile.GetPositionCap(order.AmmIndex.Int64(), trader)
if hu.Abs(hu.Add(posSize, order.BaseAssetQuantity)).Cmp(posCap) == 1 {
response.Err = ErrOverPositionCap.Error()
return
}
}

return response
}

Expand Down
21 changes: 21 additions & 0 deletions precompile/contracts/juror/limit_orders.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
hu "github.com/ava-labs/subnet-evm/plugin/evm/orderbook/hubbleutils"
b "github.com/ava-labs/subnet-evm/precompile/contracts/bibliophile"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/math"
)

func ValidatePlaceLimitOrder(bibliophile b.BibliophileClient, inputStruct *ValidatePlaceLimitOrderInput) (response ValidatePlaceLimitOrderOutput) {
Expand Down Expand Up @@ -62,6 +63,13 @@ func ValidatePlaceLimitOrder(bibliophile b.BibliophileClient, inputStruct *Valid
return
}

if bibliophile.GetPrecompileVersion(common.HexToAddress(SelfAddress)).Cmp(big.NewInt(1)) >= 0 {
if isOverPositionCap(bibliophile, trader, order.AmmIndex, order.BaseAssetQuantity) {
response.Err = ErrOverPositionCap.Error()
return
}
}

var orderSide Side = Side(Long)
if order.BaseAssetQuantity.Sign() == -1 {
orderSide = Side(Short)
Expand Down Expand Up @@ -181,3 +189,16 @@ func ILimitOrderBookOrderToLimitOrder(o *ILimitOrderBookOrder) *ob.LimitOrder {
func GetLimitOrderHashFromContractStruct(o *ILimitOrderBookOrder) (common.Hash, error) {
return ILimitOrderBookOrderToLimitOrder(o).Hash()
}

func isOverPositionCap(bibliophile b.BibliophileClient, trader common.Address, ammIndex *big.Int, baseAssetQuantity *big.Int) bool {
posSize := bibliophile.GetSize(bibliophile.GetMarketAddressFromMarketID(ammIndex.Int64()), &trader)
posCap := bibliophile.GetPositionCap(ammIndex.Int64(), trader)
longOpenOrdersAmount := bibliophile.GetLongOpenOrdersAmount(trader, ammIndex)
if baseAssetQuantity.Sign() == 1 {
posSize = math.BigMax(posSize, big.NewInt(0))
return baseAssetQuantity.Cmp(hu.Sub(posCap, hu.Add(posSize, longOpenOrdersAmount))) == 1
}
shortOpenOrdersAmount := bibliophile.GetShortOpenOrdersAmount(trader, ammIndex)
posSize = math.BigMax(hu.Neg(posSize), big.NewInt(0))
return hu.Neg(baseAssetQuantity).Cmp(hu.Sub(posCap, hu.Add(posSize, shortOpenOrdersAmount))) == 1
}
10 changes: 9 additions & 1 deletion precompile/contracts/juror/matching_validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ var (
ErrOpenReduceOnlyOrders = errors.New("open reduce only orders")
ErrNoTradingAuthority = errors.New("no trading authority")
ErrNoReferrer = errors.New("no referrer")
ErrOverPositionCap = errors.New("position size over max cap")
)

type BadElement uint8
Expand Down Expand Up @@ -379,6 +380,7 @@ func validateLimitOrderLike(bibliophile b.BibliophileClient, order *hu.BaseOrder
}

market := bibliophile.GetMarketAddressFromMarketID(order.AmmIndex.Int64())
posSize := bibliophile.GetSize(market, &order.Trader)
if side == Long {
if order.BaseAssetQuantity.Sign() <= 0 {
return ErrNotLongOrder
Expand All @@ -390,7 +392,6 @@ func validateLimitOrderLike(bibliophile b.BibliophileClient, order *hu.BaseOrder
return ErrOverFill
}
if order.ReduceOnly {
posSize := bibliophile.GetSize(market, &order.Trader)
// posSize should be closed to continue to be Short
// this also returns err if posSize >= 0, which should not happen because we are executing a long reduceOnly order on this account
if new(big.Int).Add(posSize, fillAmount).Sign() > 0 {
Expand Down Expand Up @@ -418,6 +419,13 @@ func validateLimitOrderLike(bibliophile b.BibliophileClient, order *hu.BaseOrder
} else {
return errors.New("invalid side")
}

if bibliophile.GetPrecompileVersion(common.HexToAddress(SelfAddress)).Cmp(big.NewInt(1)) >= 0 {
posCap := bibliophile.GetPositionCap(order.AmmIndex.Int64(), order.Trader)
if hu.Abs(hu.Add(posSize, order.BaseAssetQuantity)).Cmp(posCap) == 1 {
return ErrOverPositionCap
}
}
return nil
}

Expand Down
3 changes: 2 additions & 1 deletion precompile/contracts/juror/module.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,12 @@ var _ contract.Configurator = &configurator{}
// ConfigKey is the key used in json config files to specify this precompile precompileconfig.
// must be unique across all precompiles.
const ConfigKey = "jurorConfig"
const SelfAddress = "0x03000000000000000000000000000000000000a0"

// ContractAddress is the defined address of the precompile contract.
// This should be unique across all precompile contracts.
// See precompile/registry/registry.go for registered precompile contracts and more information.
var ContractAddress = common.HexToAddress("0x03000000000000000000000000000000000000a0") // SET A SUITABLE HEX ADDRESS HERE
var ContractAddress = common.HexToAddress(SelfAddress) // SET A SUITABLE HEX ADDRESS HERE

// Module is the precompile module. It is used to register the precompile contract.
var Module = modules.Module{
Expand Down