code.vegaprotocol.io/vega@v0.79.0/core/liquidity/target/snapshot.go (about)

     1  // Copyright (C) 2023 Gobalsky Labs Limited
     2  //
     3  // This program is free software: you can redistribute it and/or modify
     4  // it under the terms of the GNU Affero General Public License as
     5  // published by the Free Software Foundation, either version 3 of the
     6  // License, or (at your option) any later version.
     7  //
     8  // This program is distributed in the hope that it will be useful,
     9  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    10  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    11  // GNU Affero General Public License for more details.
    12  //
    13  // You should have received a copy of the GNU Affero General Public License
    14  // along with this program.  If not, see <http://www.gnu.org/licenses/>.
    15  
    16  package target
    17  
    18  import (
    19  	"context"
    20  	"time"
    21  
    22  	"code.vegaprotocol.io/vega/core/types"
    23  	"code.vegaprotocol.io/vega/libs/num"
    24  	"code.vegaprotocol.io/vega/libs/proto"
    25  	snapshot "code.vegaprotocol.io/vega/protos/vega/snapshot/v1"
    26  )
    27  
    28  func newTimestampedOISnapshotFromProto(s *snapshot.TimestampedOpenInterest) timestampedOI {
    29  	return timestampedOI{
    30  		Time: time.Unix(0, s.Time),
    31  		OI:   s.OpenInterest,
    32  	}
    33  }
    34  
    35  func (toi timestampedOI) toSnapshotProto() *snapshot.TimestampedOpenInterest {
    36  	return &snapshot.TimestampedOpenInterest{
    37  		OpenInterest: toi.OI,
    38  		Time:         toi.Time.UnixNano(),
    39  	}
    40  }
    41  
    42  type SnapshotEngine struct {
    43  	*Engine
    44  	data    []byte
    45  	stopped bool
    46  	key     string
    47  	keys    []string
    48  }
    49  
    50  func NewSnapshotEngine(
    51  	parameters types.TargetStakeParameters,
    52  	oiCalc OpenInterestCalculator,
    53  	marketID string,
    54  	positionFactor num.Decimal,
    55  ) *SnapshotEngine {
    56  	key := (&types.PayloadLiquidityTarget{
    57  		Target: &snapshot.LiquidityTarget{MarketId: marketID},
    58  	}).Key()
    59  
    60  	return &SnapshotEngine{
    61  		Engine: NewEngine(parameters, oiCalc, marketID, positionFactor),
    62  		key:    key,
    63  		keys:   []string{key},
    64  	}
    65  }
    66  
    67  func (e *SnapshotEngine) UpdateParameters(parameters types.TargetStakeParameters) {
    68  	e.Engine.UpdateParameters(parameters)
    69  }
    70  
    71  func (e *SnapshotEngine) StopSnapshots() {
    72  	e.stopped = true
    73  }
    74  
    75  func (e *SnapshotEngine) RecordOpenInterest(oi uint64, now time.Time) error {
    76  	if err := e.Engine.RecordOpenInterest(oi, now); err != nil {
    77  		return err
    78  	}
    79  
    80  	return nil
    81  }
    82  
    83  func (e *SnapshotEngine) GetTargetStake(rf types.RiskFactor, now time.Time, markPrice *num.Uint) *num.Uint {
    84  	ts, _ := e.Engine.GetTargetStake(rf, now, markPrice)
    85  
    86  	return ts
    87  }
    88  
    89  func (e *SnapshotEngine) GetTheoreticalTargetStake(rf types.RiskFactor, now time.Time, markPrice *num.Uint, trades []*types.Trade) *num.Uint {
    90  	tts, _ := e.Engine.GetTheoreticalTargetStake(rf, now, markPrice, trades)
    91  	return tts
    92  }
    93  
    94  func (e *SnapshotEngine) Namespace() types.SnapshotNamespace {
    95  	return types.LiquidityTargetSnapshot
    96  }
    97  
    98  func (e *SnapshotEngine) Keys() []string {
    99  	return e.keys
   100  }
   101  
   102  func (e *SnapshotEngine) Stopped() bool {
   103  	return e.stopped
   104  }
   105  
   106  func (e *SnapshotEngine) GetState(k string) ([]byte, []types.StateProvider, error) {
   107  	if k != e.key {
   108  		return nil, nil, types.ErrSnapshotKeyDoesNotExist
   109  	}
   110  
   111  	state, err := e.serialise()
   112  	return state, nil, err
   113  }
   114  
   115  func (e *SnapshotEngine) LoadState(_ context.Context, payload *types.Payload) ([]types.StateProvider, error) {
   116  	if e.Namespace() != payload.Data.Namespace() {
   117  		return nil, types.ErrInvalidSnapshotNamespace
   118  	}
   119  
   120  	switch pl := payload.Data.(type) {
   121  	case *types.PayloadLiquidityTarget:
   122  
   123  		// Check the payload is for this market
   124  		if e.marketID != pl.Target.MarketId {
   125  			return nil, types.ErrUnknownSnapshotType
   126  		}
   127  
   128  		e.now = time.Unix(0, pl.Target.CurrentTime)
   129  		e.scheduledTruncate = time.Unix(0, pl.Target.ScheduledTruncate)
   130  		e.current = pl.Target.CurrentOpenInterests
   131  		e.previous = make([]timestampedOI, 0, len(pl.Target.PreviousOpenInterests))
   132  		e.max = newTimestampedOISnapshotFromProto(pl.Target.MaxOpenInterests)
   133  
   134  		for _, poi := range pl.Target.PreviousOpenInterests {
   135  			e.previous = append(e.previous, newTimestampedOISnapshotFromProto(poi))
   136  		}
   137  
   138  		var err error
   139  		e.data, err = proto.Marshal(payload.IntoProto())
   140  		return nil, err
   141  
   142  	default:
   143  		return nil, types.ErrUnknownSnapshotType
   144  	}
   145  }
   146  
   147  func (e *SnapshotEngine) serialisePrevious() []*snapshot.TimestampedOpenInterest {
   148  	poi := make([]*snapshot.TimestampedOpenInterest, 0, len(e.previous))
   149  	for _, p := range e.previous {
   150  		poi = append(poi, p.toSnapshotProto())
   151  	}
   152  	return poi
   153  }
   154  
   155  // serialise marshal the snapshot state, populating the data fields
   156  // with updated values.
   157  func (e *SnapshotEngine) serialise() ([]byte, error) {
   158  	if e.stopped {
   159  		return nil, nil
   160  	}
   161  
   162  	p := &snapshot.Payload{
   163  		Data: &snapshot.Payload_LiquidityTarget{
   164  			LiquidityTarget: &snapshot.LiquidityTarget{
   165  				MarketId:              e.marketID,
   166  				CurrentTime:           e.now.UnixNano(),
   167  				ScheduledTruncate:     e.scheduledTruncate.UnixNano(),
   168  				CurrentOpenInterests:  e.current,
   169  				PreviousOpenInterests: e.serialisePrevious(),
   170  				MaxOpenInterests:      e.max.toSnapshotProto(),
   171  			},
   172  		},
   173  	}
   174  
   175  	var err error
   176  	e.data, err = proto.Marshal(p)
   177  	if err != nil {
   178  		return nil, err
   179  	}
   180  	return e.data, nil
   181  }