code.vegaprotocol.io/vega@v0.79.0/datanode/entities/reward.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 entities
    17  
    18  import (
    19  	"encoding/json"
    20  	"fmt"
    21  	"strconv"
    22  	"time"
    23  
    24  	"code.vegaprotocol.io/vega/libs/ptr"
    25  	v2 "code.vegaprotocol.io/vega/protos/data-node/api/v2"
    26  	"code.vegaprotocol.io/vega/protos/vega"
    27  	eventspb "code.vegaprotocol.io/vega/protos/vega/events/v1"
    28  
    29  	"github.com/shopspring/decimal"
    30  )
    31  
    32  type Reward struct {
    33  	PartyID            PartyID
    34  	AssetID            AssetID
    35  	MarketID           MarketID
    36  	EpochID            int64
    37  	Amount             decimal.Decimal
    38  	QuantumAmount      decimal.Decimal
    39  	PercentOfTotal     float64
    40  	RewardType         string
    41  	Timestamp          time.Time
    42  	TxHash             TxHash
    43  	VegaTime           time.Time
    44  	SeqNum             uint64
    45  	LockedUntilEpochID int64
    46  	GameID             *GameID
    47  	TeamID             *TeamID
    48  }
    49  
    50  type RewardTotals struct {
    51  	GameID              GameID
    52  	PartyID             PartyID
    53  	AssetID             AssetID
    54  	MarketID            MarketID
    55  	EpochID             int64
    56  	TeamID              TeamID
    57  	TotalRewards        decimal.Decimal
    58  	TotalRewardsQuantum decimal.Decimal
    59  }
    60  
    61  func (r Reward) String() string {
    62  	return fmt.Sprintf("{Epoch: %v, Party: %s, Asset: %s, Amount: %v}",
    63  		r.EpochID, r.PartyID, r.AssetID, r.Amount)
    64  }
    65  
    66  func (r Reward) ToProto() *vega.Reward {
    67  	var gameID, teamID *string
    68  	if r.GameID != nil && *r.GameID != "" {
    69  		gameID = ptr.From(r.GameID.String())
    70  	}
    71  
    72  	if r.TeamID != nil && *r.TeamID != "" {
    73  		teamID = ptr.From(r.TeamID.String())
    74  	}
    75  
    76  	protoReward := vega.Reward{
    77  		PartyId:           r.PartyID.String(),
    78  		AssetId:           r.AssetID.String(),
    79  		Epoch:             uint64(r.EpochID),
    80  		Amount:            r.Amount.String(),
    81  		QuantumAmount:     r.QuantumAmount.String(),
    82  		PercentageOfTotal: fmt.Sprintf("%v", r.PercentOfTotal),
    83  		ReceivedAt:        r.Timestamp.UnixNano(),
    84  		RewardType:        r.RewardType,
    85  		LockedUntilEpoch:  uint64(r.LockedUntilEpochID),
    86  		GameId:            gameID,
    87  		TeamId:            teamID,
    88  	}
    89  	return &protoReward
    90  }
    91  
    92  func (r Reward) Cursor() *Cursor {
    93  	cursor := RewardCursor{
    94  		PartyID: r.PartyID.String(),
    95  		AssetID: r.AssetID.String(),
    96  		EpochID: r.EpochID,
    97  	}
    98  	return NewCursor(cursor.String())
    99  }
   100  
   101  func (r Reward) ToProtoEdge(_ ...any) (*v2.RewardEdge, error) {
   102  	return &v2.RewardEdge{
   103  		Node:   r.ToProto(),
   104  		Cursor: r.Cursor().Encode(),
   105  	}, nil
   106  }
   107  
   108  func RewardFromProto(pr eventspb.RewardPayoutEvent, txHash TxHash, vegaTime time.Time, seqNum uint64) (Reward, error) {
   109  	epochID, err := strconv.ParseInt(pr.EpochSeq, 10, 64)
   110  	if err != nil {
   111  		return Reward{}, fmt.Errorf("could not parse epoch %q: %w", pr.EpochSeq, err)
   112  	}
   113  
   114  	percentOfTotal, err := strconv.ParseFloat(pr.PercentOfTotalReward, 64)
   115  	if err != nil {
   116  		return Reward{}, fmt.Errorf("could not parse percent of total reward %q: %w", pr.PercentOfTotalReward, err)
   117  	}
   118  
   119  	amount, err := decimal.NewFromString(pr.Amount)
   120  	if err != nil {
   121  		return Reward{}, fmt.Errorf("could not parse amount of reward %q: %w", pr.Amount, err)
   122  	}
   123  
   124  	quantumAmount, err := decimal.NewFromString(pr.QuantumAmount)
   125  	if err != nil {
   126  		return Reward{}, fmt.Errorf("could not parse the amount of reward %q: %w", pr.QuantumAmount, err)
   127  	}
   128  
   129  	lockedUntilEpochID := epochID
   130  	if len(pr.LockedUntilEpoch) > 0 {
   131  		lockedUntilEpochID, err = strconv.ParseInt(pr.LockedUntilEpoch, 10, 64)
   132  		if err != nil {
   133  			return Reward{}, fmt.Errorf("parsing locked until epoch %q: %w", pr.LockedUntilEpoch, err)
   134  		}
   135  	}
   136  
   137  	var gameID *GameID
   138  	if pr.GameId != nil {
   139  		gameID = ptr.From(GameID(*pr.GameId))
   140  	}
   141  
   142  	reward := Reward{
   143  		PartyID:            PartyID(pr.Party),
   144  		AssetID:            AssetID(pr.Asset),
   145  		EpochID:            epochID,
   146  		Amount:             amount,
   147  		QuantumAmount:      quantumAmount,
   148  		PercentOfTotal:     percentOfTotal,
   149  		Timestamp:          NanosToPostgresTimestamp(pr.Timestamp),
   150  		RewardType:         pr.RewardType,
   151  		TxHash:             txHash,
   152  		VegaTime:           vegaTime,
   153  		SeqNum:             seqNum,
   154  		LockedUntilEpochID: lockedUntilEpochID,
   155  		GameID:             gameID,
   156  		// We are not expecting TeamID to be set in the proto from core, but the API will populate it
   157  		// if the reward is for a team game.
   158  	}
   159  
   160  	return reward, nil
   161  }
   162  
   163  type RewardCursor struct {
   164  	PartyID string `json:"party_id"`
   165  	AssetID string `json:"asset_id"`
   166  	EpochID int64  `json:"epoch_id"`
   167  }
   168  
   169  func (rc RewardCursor) String() string {
   170  	bs, err := json.Marshal(rc)
   171  	if err != nil {
   172  		// This should never happen.
   173  		panic(fmt.Errorf("marshalling reward cursor: %w", err))
   174  	}
   175  	return string(bs)
   176  }
   177  
   178  func (rc *RewardCursor) Parse(cursorString string) error {
   179  	if cursorString == "" {
   180  		return nil
   181  	}
   182  	return json.Unmarshal([]byte(cursorString), rc)
   183  }