From 832158d96d14375a9ab79f118ee4356a65c7532c Mon Sep 17 00:00:00 2001 From: Shubham Goyal Date: Sun, 12 May 2024 16:29:52 +0530 Subject: [PATCH] Get fresh hubble state --- plugin/evm/limit_order.go | 9 ------- plugin/evm/orderbook/config_service.go | 6 +++++ plugin/evm/orderbook/hubbleutils/config.go | 24 ------------------- .../evm/orderbook/hubbleutils/margin_math.go | 1 + plugin/evm/orderbook/liquidations.go | 1 + plugin/evm/orderbook/matching_pipeline.go | 10 ++++++-- plugin/evm/orderbook/memory_database.go | 7 ++++-- plugin/evm/orderbook/mocks.go | 4 ++++ plugin/evm/orderbook/state.go | 23 ++++++++++++++++++ plugin/evm/orderbook/trading_apis.go | 5 ++++ .../contracts/bibliophile/clearing_house.go | 4 ++-- 11 files changed, 55 insertions(+), 39 deletions(-) create mode 100644 plugin/evm/orderbook/state.go diff --git a/plugin/evm/limit_order.go b/plugin/evm/limit_order.go index eb5e20c107..94d6628d4f 100644 --- a/plugin/evm/limit_order.go +++ b/plugin/evm/limit_order.go @@ -77,15 +77,6 @@ func NewLimitOrderProcesser(ctx *snow.Context, txPool *txpool.TxPool, shutdownCh matchingPipeline := orderbook.NewMatchingPipeline(memoryDb, lotp, configService) // if any of the following values are changed, the nodes will need to be restarted. // This is also true for local testing. once contracts are deployed it's mandatory to restart the nodes - hState := &hu.HubbleState{ - Assets: matchingPipeline.GetCollaterals(), - ActiveMarkets: matchingPipeline.GetActiveMarkets(), - MinAllowableMargin: configService.GetMinAllowableMargin(), - MaintenanceMargin: configService.GetMaintenanceMargin(), - TakerFee: configService.GetTakerFee(), - UpgradeVersion: hu.V2, - } - hu.SetHubbleState(hState) hu.SetChainIdAndVerifyingSignedOrdersContract(backend.ChainConfig().ChainID.Int64(), signedObAddy.String()) filterSystem := filters.NewFilterSystem(backend, filters.Config{}) diff --git a/plugin/evm/orderbook/config_service.go b/plugin/evm/orderbook/config_service.go index d87ab2b362..4060eb3293 100644 --- a/plugin/evm/orderbook/config_service.go +++ b/plugin/evm/orderbook/config_service.go @@ -35,6 +35,8 @@ type IConfigService interface { GetMarketAddressFromMarketID(marketId int64) common.Address GetImpactMarginNotional(ammAddress common.Address) *big.Int GetReduceOnlyAmounts(trader common.Address) []*big.Int + + IsSettledAll() bool } type ConfigService struct { @@ -152,3 +154,7 @@ func (cs *ConfigService) GetImpactMarginNotional(ammAddress common.Address) *big func (cs *ConfigService) GetReduceOnlyAmounts(trader common.Address) []*big.Int { return bibliophile.GetReduceOnlyAmounts(cs.getStateAtCurrentBlock(), trader) } + +func (cs *ConfigService) IsSettledAll() bool { + return bibliophile.IsSettledAll(cs.getStateAtCurrentBlock()) +} diff --git a/plugin/evm/orderbook/hubbleutils/config.go b/plugin/evm/orderbook/hubbleutils/config.go index 17e4931e78..d27f9e0c84 100644 --- a/plugin/evm/orderbook/hubbleutils/config.go +++ b/plugin/evm/orderbook/hubbleutils/config.go @@ -1,35 +1,11 @@ package hubbleutils -import "math/big" - var ( ChainId int64 VerifyingContract string - hState *HubbleState ) func SetChainIdAndVerifyingSignedOrdersContract(chainId int64, verifyingContract string) { ChainId = chainId VerifyingContract = verifyingContract } - -func SetHubbleState(_hState *HubbleState) { - hState = _hState -} - -func GetHubbleState() *HubbleState { - assets := make([]Collateral, len(hState.Assets)) - copy(assets, hState.Assets) - - activeMarkets := make([]Market, len(hState.ActiveMarkets)) - copy(activeMarkets, hState.ActiveMarkets) - - return &HubbleState{ - Assets: assets, - ActiveMarkets: activeMarkets, - MinAllowableMargin: new(big.Int).Set(hState.MinAllowableMargin), - MaintenanceMargin: new(big.Int).Set(hState.MaintenanceMargin), - TakerFee: new(big.Int).Set(hState.TakerFee), - UpgradeVersion: hState.UpgradeVersion, - } -} diff --git a/plugin/evm/orderbook/hubbleutils/margin_math.go b/plugin/evm/orderbook/hubbleutils/margin_math.go index 007432447c..69d180b5f8 100644 --- a/plugin/evm/orderbook/hubbleutils/margin_math.go +++ b/plugin/evm/orderbook/hubbleutils/margin_math.go @@ -65,6 +65,7 @@ func GetNotionalPositionAndMargin(hState *HubbleState, userState *UserState, mar return notionalPosition, Add(margin, unrealizedPnl) } +// SUNSET: `hState.ActiveMarkets` in the hState passed contains settled markets too func GetTotalNotionalPositionAndUnrealizedPnl(hState *HubbleState, userState *UserState, margin *big.Int, marginMode MarginMode) (*big.Int, *big.Int) { notionalPosition := big.NewInt(0) unrealizedPnl := big.NewInt(0) diff --git a/plugin/evm/orderbook/liquidations.go b/plugin/evm/orderbook/liquidations.go index 152aa4dec8..fe4a2bfb11 100644 --- a/plugin/evm/orderbook/liquidations.go +++ b/plugin/evm/orderbook/liquidations.go @@ -23,6 +23,7 @@ func (liq LiquidablePosition) GetUnfilledSize() *big.Int { } func calcMarginFraction(trader *Trader, hState *hu.HubbleState) *big.Int { + // SUNSET: this function is only used in unit tests and a test API; no need to change it userState := &hu.UserState{ Positions: translatePositions(trader.Positions), Margins: getMargins(trader, len(hState.Assets)), diff --git a/plugin/evm/orderbook/matching_pipeline.go b/plugin/evm/orderbook/matching_pipeline.go index 8a821ccb5c..f8e9769893 100644 --- a/plugin/evm/orderbook/matching_pipeline.go +++ b/plugin/evm/orderbook/matching_pipeline.go @@ -65,6 +65,7 @@ func (pipeline *MatchingPipeline) Run(blockNumber *big.Int) bool { // reset ticker pipeline.MatchingTicker.Reset(matchingTickerDuration) + // SUNSET: this is ok, we can skip matching, liquidation, settleFunding, commitSampleLiquidity when markets are settled markets := pipeline.GetActiveMarkets() log.Info("MatchingPipeline:Run", "blockNumber", blockNumber) @@ -93,7 +94,7 @@ func (pipeline *MatchingPipeline) Run(blockNumber *big.Int) bool { } // fetch various hubble market params and run the matching engine - hState := hu.GetHubbleState() + hState := GetHubbleState(pipeline.configService) hState.OraclePrices = hu.ArrayToMap(pipeline.configService.GetUnderlyingPrices()) // build trader map @@ -123,6 +124,7 @@ func (pipeline *MatchingPipeline) GetOrderMatchingTransactions(blockNumber *big. pipeline.mu.Lock() defer pipeline.mu.Unlock() + // SUNSET: ok to skip when markets are settled activeMarkets := pipeline.GetActiveMarkets() log.Info("MatchingPipeline:GetOrderMatchingTransactions") @@ -134,7 +136,7 @@ func (pipeline *MatchingPipeline) GetOrderMatchingTransactions(blockNumber *big. pipeline.lotp.PurgeOrderBookTxs() // fetch various hubble market params and run the matching engine - hState := hu.GetHubbleState() + hState := GetHubbleState(pipeline.configService) hState.OraclePrices = hu.ArrayToMap(pipeline.configService.GetUnderlyingPrices()) marginMap := make(map[common.Address]*big.Int) @@ -228,11 +230,15 @@ func (pipeline *MatchingPipeline) runLiquidations(liquidablePositions []Liquidab log.Info("found positions to liquidate", "num", len(liquidablePositions)) // we need to retreive permissible bounds for liquidations in each market + // SUNSET: this is ok, we can skip liquidations when markets are settled markets := pipeline.GetActiveMarkets() type S struct { Upperbound *big.Int Lowerbound *big.Int } + if len(markets) == 0 { + return + } liquidationBounds := make([]S, len(markets)) for _, market := range markets { upperbound, lowerbound := pipeline.configService.GetAcceptableBoundsForLiquidation(market) diff --git a/plugin/evm/orderbook/memory_database.go b/plugin/evm/orderbook/memory_database.go index 61910ccc7b..c7e412c079 100644 --- a/plugin/evm/orderbook/memory_database.go +++ b/plugin/evm/orderbook/memory_database.go @@ -293,6 +293,7 @@ func (db *InMemoryDatabase) Accept(acceptedBlockNumber, blockTimestamp uint64) { defer db.mu.Unlock() log.Info("Accept", "acceptedBlockNumber", acceptedBlockNumber, "blockTimestamp", blockTimestamp) + // SUNSET: this will work with 0 markets count := db.configService.GetActiveMarketsCount() for m := int64(0); m < count; m++ { longOrders := db.getLongOrdersWithoutLock(Market(m), nil, nil, false) @@ -590,7 +591,8 @@ func (db *InMemoryDatabase) UpdateFilledBaseAssetQuantity(quantity *big.Int, ord // only update margin if the order is not reduce-only if order.OrderType == Signed && !order.ReduceOnly { - minAllowableMargin := hu.GetHubbleState().MinAllowableMargin + hState := GetHubbleState(db.configService) + minAllowableMargin := hState.MinAllowableMargin requiredMargin := hu.GetRequiredMargin(order.Price, quantity, minAllowableMargin, big.NewInt(0)) db.updateVirtualReservedMargin(order.Trader, hu.Neg(requiredMargin)) @@ -1335,7 +1337,7 @@ func (db *InMemoryDatabase) GetMarginAvailableForMakerbook(trader common.Address return big.NewInt(0) } - hState := hu.GetHubbleState() + hState := GetHubbleState(db.configService) hState.OraclePrices = prices userState := &hu.UserState{ Positions: translatePositions(_trader.Positions), @@ -1353,6 +1355,7 @@ func (db *InMemoryDatabase) SampleImpactPrice() (impactBids, impactAsks, midPric db.mu.RLock() defer db.mu.RUnlock() + // SUNSET: code will not reach here when markets are settled count := db.configService.GetActiveMarketsCount() impactBids = make([]*big.Int, count) impactAsks = make([]*big.Int, count) diff --git a/plugin/evm/orderbook/mocks.go b/plugin/evm/orderbook/mocks.go index 7a89f5155e..6a56abde82 100644 --- a/plugin/evm/orderbook/mocks.go +++ b/plugin/evm/orderbook/mocks.go @@ -347,3 +347,7 @@ func (cs *MockConfigService) GetImpactMarginNotional(ammAddress common.Address) func (cs *MockConfigService) GetReduceOnlyAmounts(trader common.Address) []*big.Int { return []*big.Int{big.NewInt(0)} } + +func (cs *MockConfigService) IsSettledAll() bool { + return false +} diff --git a/plugin/evm/orderbook/state.go b/plugin/evm/orderbook/state.go new file mode 100644 index 0000000000..b77ef9e1a4 --- /dev/null +++ b/plugin/evm/orderbook/state.go @@ -0,0 +1,23 @@ +package orderbook + +import ( + hu "github.com/ava-labs/subnet-evm/plugin/evm/orderbook/hubbleutils" +) + +func GetHubbleState(configService IConfigService) *hu.HubbleState { + count := configService.GetActiveMarketsCount() + markets := make([]Market, count) + for i := int64(0); i < count; i++ { + markets[i] = Market(i) + } + hState := &hu.HubbleState{ + Assets: configService.GetCollaterals(), + ActiveMarkets: markets, + MinAllowableMargin: configService.GetMinAllowableMargin(), + MaintenanceMargin: configService.GetMaintenanceMargin(), + TakerFee: configService.GetTakerFee(), + UpgradeVersion: hu.V2, + } + + return hState +} diff --git a/plugin/evm/orderbook/trading_apis.go b/plugin/evm/orderbook/trading_apis.go index 080c9fbcb8..296fe72131 100644 --- a/plugin/evm/orderbook/trading_apis.go +++ b/plugin/evm/orderbook/trading_apis.go @@ -194,6 +194,7 @@ func (api *TradingAPI) GetMarginAndPositions(ctx context.Context, trader string) return response, fmt.Errorf("trader not found") } + // SUNSET: need to fetch total market count here, not active markets(cuz we're fetching pending funding) count := api.configService.GetActiveMarketsCount() markets := make([]Market, count) for i := int64(0); i < count; i++ { @@ -336,6 +337,10 @@ func (api *TradingAPI) StreamMarketTrades(ctx context.Context, market Market, bl // @todo cache api.configService values to avoid db lookups on every order placement func (api *TradingAPI) PlaceOrder(order *hu.SignedOrder) (common.Hash, bool, error) { + if api.configService.IsSettledAll() { + return common.Hash{}, false, errors.New("all markets are settled now") + } + orderId, err := order.Hash() if err != nil { return common.Hash{}, false, fmt.Errorf("failed to hash order: %s", err) diff --git a/precompile/contracts/bibliophile/clearing_house.go b/precompile/contracts/bibliophile/clearing_house.go index 83de44bb52..b1d6db2445 100644 --- a/precompile/contracts/bibliophile/clearing_house.go +++ b/precompile/contracts/bibliophile/clearing_house.go @@ -39,7 +39,7 @@ func marketsStorageSlot() *big.Int { } func GetActiveMarketsCount(stateDB contract.StateDB) int64 { - if isSettledAll(stateDB) { + if IsSettledAll(stateDB) { return 0 } return GetMarketsCountRaw(stateDB) @@ -50,7 +50,7 @@ func GetMarketsCountRaw(stateDB contract.StateDB) int64 { return new(big.Int).SetBytes(rawVal.Bytes()).Int64() } -func isSettledAll(stateDB contract.StateDB) bool { +func IsSettledAll(stateDB contract.StateDB) bool { return stateDB.GetState(common.HexToAddress(CLEARING_HOUSE_GENESIS_ADDRESS), common.BigToHash(big.NewInt(SETTLED_ALL_SLOT))).Big().Sign() == 1 }