Skip to content

Commit

Permalink
handle settled markets (#190)
Browse files Browse the repository at this point in the history
* handle settled markets

* Get fresh hubble state (#191)

* misc

* fix settlement price slot

---------

Co-authored-by: Shubham <[email protected]>
  • Loading branch information
atvanguard and lumos42 authored May 19, 2024
1 parent d884795 commit 3b29c1a
Show file tree
Hide file tree
Showing 12 changed files with 133 additions and 53 deletions.
9 changes: 0 additions & 9 deletions plugin/evm/limit_order.go
Original file line number Diff line number Diff line change
Expand Up @@ -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{})
Expand Down
20 changes: 18 additions & 2 deletions plugin/evm/orderbook/config_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,10 @@ type IConfigService interface {
getMinSizeRequirement(market Market) *big.Int
GetPriceMultiplier(market Market) *big.Int
GetActiveMarketsCount() int64
GetMarketsIncludingSettled() []common.Address
GetUnderlyingPrices() []*big.Int
GetMidPrices() []*big.Int
GetSettlementPrices() []*big.Int
GetCollaterals() []hu.Collateral
GetLastPremiumFraction(market Market, trader *common.Address) *big.Int
GetCumulativePremiumFraction(market Market) *big.Int
Expand All @@ -35,6 +37,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 {
Expand Down Expand Up @@ -98,6 +102,10 @@ func (cs *ConfigService) GetActiveMarketsCount() int64 {
return bibliophile.GetActiveMarketsCount(cs.getStateAtCurrentBlock())
}

func (cs *ConfigService) GetMarketsIncludingSettled() []common.Address {
return bibliophile.GetMarketsIncludingSettled(cs.getStateAtCurrentBlock())
}

func (cs *ConfigService) GetUnderlyingPrices() []*big.Int {
return bibliophile.GetUnderlyingPrices(cs.getStateAtCurrentBlock())
}
Expand All @@ -106,17 +114,21 @@ func (cs *ConfigService) GetMidPrices() []*big.Int {
return bibliophile.GetMidPrices(cs.getStateAtCurrentBlock())
}

func (cs *ConfigService) GetSettlementPrices() []*big.Int {
return bibliophile.GetSettlementPrices(cs.getStateAtCurrentBlock())
}

func (cs *ConfigService) GetCollaterals() []hu.Collateral {
return bibliophile.GetCollaterals(cs.getStateAtCurrentBlock())
}

func (cs *ConfigService) GetLastPremiumFraction(market Market, trader *common.Address) *big.Int {
markets := bibliophile.GetMarkets(cs.getStateAtCurrentBlock())
markets := bibliophile.GetMarketsIncludingSettled(cs.getStateAtCurrentBlock())
return bibliophile.GetLastPremiumFraction(cs.getStateAtCurrentBlock(), markets[market], trader)
}

func (cs *ConfigService) GetCumulativePremiumFraction(market Market) *big.Int {
markets := bibliophile.GetMarkets(cs.getStateAtCurrentBlock())
markets := bibliophile.GetMarketsIncludingSettled(cs.getStateAtCurrentBlock())
return bibliophile.GetCumulativePremiumFraction(cs.getStateAtCurrentBlock(), markets[market])
}

Expand Down Expand Up @@ -152,3 +164,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())
}
24 changes: 0 additions & 24 deletions plugin/evm/orderbook/hubbleutils/config.go
Original file line number Diff line number Diff line change
@@ -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,
}
}
9 changes: 8 additions & 1 deletion plugin/evm/orderbook/hubbleutils/margin_math.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ type HubbleState struct {
Assets []Collateral
OraclePrices map[Market]*big.Int
MidPrices map[Market]*big.Int
SettlementPrices map[Market]*big.Int
ActiveMarkets []Market
MinAllowableMargin *big.Int
MaintenanceMargin *big.Int
Expand Down Expand Up @@ -64,6 +65,7 @@ func GetNotionalPositionAndMargin(hState *HubbleState, userState *UserState, mar
return notionalPosition, Add(margin, unrealizedPnl)
}

// SUNSET: `hState.ActiveMarkets` contains active markets and ` hState.SettlementPrices` contains settlement prices
func GetTotalNotionalPositionAndUnrealizedPnl(hState *HubbleState, userState *UserState, margin *big.Int, marginMode MarginMode) (*big.Int, *big.Int) {
notionalPosition := big.NewInt(0)
unrealizedPnl := big.NewInt(0)
Expand All @@ -81,9 +83,14 @@ func getOptimalPnl(hState *HubbleState, position *Position, margin *big.Int, mar
return big.NewInt(0), big.NewInt(0)
}

price := hState.OraclePrices[market]
if hState.SettlementPrices[market] != nil && hState.SettlementPrices[market].Sign() != 0 {
price = hState.SettlementPrices[market]
}

// based on oracle price
oracleBasedNotional, oracleBasedUnrealizedPnl, oracleBasedMF := GetPositionMetadata(
hState.OraclePrices[market],
price,
position.OpenNotional,
position.Size,
margin,
Expand Down
1 change: 1 addition & 0 deletions plugin/evm/orderbook/liquidations.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)),
Expand Down
11 changes: 8 additions & 3 deletions plugin/evm/orderbook/matching_pipeline.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down Expand Up @@ -93,8 +94,7 @@ func (pipeline *MatchingPipeline) Run(blockNumber *big.Int) bool {
}

// fetch various hubble market params and run the matching engine
hState := hu.GetHubbleState()
hState.OraclePrices = hu.ArrayToMap(pipeline.configService.GetUnderlyingPrices())
hState := GetHubbleState(pipeline.configService)

// build trader map
liquidablePositions, ordersToCancel, marginMap := pipeline.db.GetNaughtyTraders(hState)
Expand Down Expand Up @@ -123,6 +123,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")

Expand All @@ -134,7 +135,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)
Expand Down Expand Up @@ -228,11 +229,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)
Expand Down
7 changes: 5 additions & 2 deletions plugin/evm/orderbook/memory_database.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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))

Expand Down Expand Up @@ -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),
Expand All @@ -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)
Expand Down
12 changes: 12 additions & 0 deletions plugin/evm/orderbook/mocks.go
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,14 @@ func (cs *MockConfigService) GetMidPrices() []*big.Int {
return []*big.Int{}
}

func (cs *MockConfigService) GetSettlementPrices() []*big.Int {
return []*big.Int{}
}

func (cs *MockConfigService) GetMarketsIncludingSettled() []common.Address {
return []common.Address{}
}

func (cs *MockConfigService) GetLastPremiumFraction(market Market, trader *common.Address) *big.Int {
return big.NewInt(0)
}
Expand Down Expand Up @@ -347,3 +355,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
}
26 changes: 26 additions & 0 deletions plugin/evm/orderbook/state.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
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(),
OraclePrices: hu.ArrayToMap(configService.GetUnderlyingPrices()),
MidPrices: hu.ArrayToMap(configService.GetMidPrices()),
SettlementPrices: hu.ArrayToMap(configService.GetSettlementPrices()),
ActiveMarkets: markets,
MinAllowableMargin: configService.GetMinAllowableMargin(),
MaintenanceMargin: configService.GetMaintenanceMargin(),
TakerFee: configService.GetTakerFee(),
UpgradeVersion: hu.V2,
}

return hState
}
6 changes: 5 additions & 1 deletion plugin/evm/orderbook/trading_apis.go
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ func (api *TradingAPI) GetMarginAndPositions(ctx context.Context, trader string)
return response, fmt.Errorf("trader not found")
}

count := api.configService.GetActiveMarketsCount()
count := int64(len(api.configService.GetMarketsIncludingSettled()))
markets := make([]Market, count)
for i := int64(0); i < count; i++ {
markets[i] = Market(i)
Expand Down Expand Up @@ -336,6 +336,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)
Expand Down
5 changes: 5 additions & 0 deletions precompile/contracts/bibliophile/amm.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ const (
ASKS_SLOT int64 = 22
BIDS_HEAD_SLOT int64 = 23
ASKS_HEAD_SLOT int64 = 24
SETTLEMENT_PRICE_SLOT int64 = 28
)

// AMM State
Expand Down Expand Up @@ -93,6 +94,10 @@ func getUnderlyingPriceForMarket(stateDB contract.StateDB, marketID int64) *big.
return getUnderlyingPrice(stateDB, market)
}

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

// Trader State

func positionsStorageSlot(trader *common.Address) *big.Int {
Expand Down
Loading

0 comments on commit 3b29c1a

Please sign in to comment.