code.vegaprotocol.io/vega@v0.79.0/datanode/entities/vote.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  	"time"
    22  
    23  	v2 "code.vegaprotocol.io/vega/protos/data-node/api/v2"
    24  	"code.vegaprotocol.io/vega/protos/vega"
    25  
    26  	"github.com/shopspring/decimal"
    27  )
    28  
    29  type PerMarketELSWeight struct {
    30  	Market string `json:"market"`
    31  	ELS    string `json:"els"`
    32  }
    33  
    34  type Vote struct {
    35  	PartyID                        PartyID
    36  	ProposalID                     ProposalID
    37  	Value                          VoteValue
    38  	TotalGovernanceTokenBalance    decimal.Decimal
    39  	TotalGovernanceTokenWeight     decimal.Decimal
    40  	TotalEquityLikeShareWeight     decimal.Decimal
    41  	PerMarketEquityLikeShareWeight []PerMarketELSWeight
    42  	InitialTime                    time.Time // First vote for this party/proposal
    43  	TxHash                         TxHash
    44  	VegaTime                       time.Time // Time of last vote update
    45  }
    46  
    47  func (v Vote) ToProto() *vega.Vote {
    48  	var perMarketELSWeight []*vega.VoteELSPair
    49  
    50  	if ln := len(v.PerMarketEquityLikeShareWeight); ln > 0 {
    51  		perMarketELSWeight = make([]*vega.VoteELSPair, 0, ln)
    52  		for _, w := range v.PerMarketEquityLikeShareWeight {
    53  			perMarketELSWeight = append(perMarketELSWeight, &vega.VoteELSPair{
    54  				MarketId: w.Market,
    55  				Els:      w.ELS,
    56  			})
    57  		}
    58  	}
    59  
    60  	return &vega.Vote{
    61  		PartyId:                     v.PartyID.String(),
    62  		ProposalId:                  v.ProposalID.String(),
    63  		Value:                       vega.Vote_Value(v.Value),
    64  		TotalGovernanceTokenBalance: v.TotalGovernanceTokenBalance.String(),
    65  		TotalGovernanceTokenWeight:  v.TotalGovernanceTokenWeight.String(),
    66  		TotalEquityLikeShareWeight:  v.TotalEquityLikeShareWeight.String(),
    67  		Timestamp:                   v.InitialTime.UnixNano(),
    68  		ElsPerMarket:                perMarketELSWeight,
    69  	}
    70  }
    71  
    72  func VoteFromProto(pv *vega.Vote, txHash TxHash) (Vote, error) {
    73  	totalGovernanceTokenBalance, err := decimal.NewFromString(pv.TotalGovernanceTokenBalance)
    74  	if err != nil {
    75  		return Vote{}, err
    76  	}
    77  
    78  	totalGovernanceTokenWeight, err := decimal.NewFromString(pv.TotalGovernanceTokenWeight)
    79  	if err != nil {
    80  		return Vote{}, err
    81  	}
    82  
    83  	totalEquityLikeShareWeight, err := decimal.NewFromString(pv.TotalEquityLikeShareWeight)
    84  	if err != nil {
    85  		return Vote{}, err
    86  	}
    87  
    88  	// We need deterministic ordering of the share weights to prevent network history segment hashes from diverting
    89  	perMarketELSWeight := make([]PerMarketELSWeight, 0)
    90  
    91  	for _, pair := range pv.ElsPerMarket {
    92  		perMarketELSWeight = append(perMarketELSWeight, PerMarketELSWeight{
    93  			Market: pair.MarketId,
    94  			ELS:    pair.Els,
    95  		})
    96  	}
    97  
    98  	v := Vote{
    99  		PartyID:                        PartyID(pv.PartyId),
   100  		ProposalID:                     ProposalID(pv.ProposalId),
   101  		Value:                          VoteValue(pv.Value),
   102  		TotalGovernanceTokenBalance:    totalGovernanceTokenBalance,
   103  		TotalGovernanceTokenWeight:     totalGovernanceTokenWeight,
   104  		TotalEquityLikeShareWeight:     totalEquityLikeShareWeight,
   105  		InitialTime:                    NanosToPostgresTimestamp(pv.Timestamp),
   106  		PerMarketEquityLikeShareWeight: perMarketELSWeight,
   107  		TxHash:                         txHash,
   108  	}
   109  
   110  	return v, nil
   111  }
   112  
   113  func (v Vote) ToProtoEdge(_ ...any) (*v2.VoteEdge, error) {
   114  	return &v2.VoteEdge{
   115  		Node:   v.ToProto(),
   116  		Cursor: v.Cursor().Encode(),
   117  	}, nil
   118  }
   119  
   120  func (v Vote) Cursor() *Cursor {
   121  	pc := VoteCursor{
   122  		PartyID:  v.PartyID,
   123  		VegaTime: v.VegaTime,
   124  	}
   125  
   126  	return NewCursor(pc.String())
   127  }
   128  
   129  type VoteCursor struct {
   130  	PartyID  PartyID   `json:"party_id"`
   131  	VegaTime time.Time `json:"vega_time"`
   132  }
   133  
   134  func (vc VoteCursor) String() string {
   135  	bs, err := json.Marshal(vc)
   136  	if err != nil {
   137  		// This should never happen.
   138  		panic(fmt.Errorf("could not marshal order cursor: %w", err))
   139  	}
   140  	return string(bs)
   141  }
   142  
   143  func (vc *VoteCursor) Parse(cursorString string) error {
   144  	if cursorString == "" {
   145  		return nil
   146  	}
   147  	return json.Unmarshal([]byte(cursorString), vc)
   148  }