github.com/DapperCollectives/CAST/backend@v0.0.0-20230921221157-1350c8be7c96/main/strategies/total_token_weighted_default.go (about)

     1  package strategies
     2  
     3  import (
     4  	"fmt"
     5  	"math"
     6  
     7  	"github.com/DapperCollectives/CAST/backend/main/models"
     8  	"github.com/DapperCollectives/CAST/backend/main/shared"
     9  	s "github.com/DapperCollectives/CAST/backend/main/shared"
    10  	"github.com/rs/zerolog/log"
    11  )
    12  
    13  type TotalTokenWeightedDefault struct {
    14  	s.StrategyStruct
    15  	DB *s.Database
    16  }
    17  
    18  func (s *TotalTokenWeightedDefault) FetchBalance(
    19  	b *models.Balance,
    20  	p *models.Proposal,
    21  ) (*models.Balance, error) {
    22  
    23  	var c models.Community
    24  	if err := c.GetCommunityByProposalId(s.DB, b.Proposal_id); err != nil {
    25  		return nil, err
    26  	}
    27  
    28  	strategy, err := models.MatchStrategyByProposal(*c.Strategies, *p.Strategy)
    29  	if err != nil {
    30  		log.Error().Err(err).Msg("Unable to find strategy for contract")
    31  		return nil, err
    32  	}
    33  
    34  	if err := s.FetchBalanceFromSnapshot(&strategy, b); err != nil {
    35  		log.Error().Err(err).Msg("Error calling snapshot client")
    36  		return nil, err
    37  	}
    38  	if err := b.CreateBalance(s.DB); err != nil {
    39  		log.Error().Err(err).Msg("Error creating balance in the database.")
    40  		return nil, err
    41  	}
    42  
    43  	return b, nil
    44  }
    45  
    46  func (s *TotalTokenWeightedDefault) FetchBalanceFromSnapshot(
    47  	strategy *models.Strategy,
    48  	b *models.Balance,
    49  ) error {
    50  
    51  	var ftBalance = &shared.FTBalanceResponse{}
    52  	ftBalance.NewFTBalance()
    53  
    54  	if *strategy.Contract.Name == "FlowToken" {
    55  		if err := s.FlowAdapter.GetAddressBalanceAtBlockHeight(
    56  			b.Addr,
    57  			b.BlockHeight,
    58  			ftBalance,
    59  			&strategy.Contract,
    60  		); err != nil {
    61  			log.Error().Err(err).Msg("Error fetching balance from snapshot client")
    62  			return err
    63  		}
    64  		b.PrimaryAccountBalance = ftBalance.PrimaryAccountBalance
    65  		b.SecondaryAccountBalance = ftBalance.SecondaryAccountBalance
    66  		b.StakingBalance = ftBalance.StakingBalance
    67  
    68  	} else {
    69  		if err := s.FlowAdapter.GetAddressBalanceAtBlockHeight(
    70  			b.Addr,
    71  			b.BlockHeight,
    72  			ftBalance,
    73  			&strategy.Contract,
    74  		); err != nil {
    75  			log.Error().Err(err).Msg("Error fetching balance.")
    76  			return err
    77  		}
    78  		b.PrimaryAccountBalance = ftBalance.Balance
    79  		b.SecondaryAccountBalance = 0
    80  		b.StakingBalance = 0
    81  	}
    82  
    83  	return nil
    84  }
    85  func (s *TotalTokenWeightedDefault) TallyVotes(
    86  	votes []*models.VoteWithBalance,
    87  	r *models.ProposalResults,
    88  	p *models.Proposal,
    89  ) (models.ProposalResults, error) {
    90  	var zero uint64 = 0
    91  
    92  	for _, vote := range votes {
    93  		if *vote.StakingBalance != zero {
    94  			var allowedBalance float64
    95  
    96  			totalBalance := float64(*vote.StakingBalance) + float64(*vote.PrimaryAccountBalance) + float64(*vote.SecondaryAccountBalance)
    97  
    98  			if p.Max_weight != nil {
    99  				allowedBalance = p.EnforceMaxWeight(totalBalance)
   100  			} else {
   101  				allowedBalance = totalBalance
   102  			}
   103  
   104  			r.Results[vote.Choice] += int(allowedBalance)
   105  			r.Results_float[vote.Choice] += allowedBalance * math.Pow(10, -8)
   106  		}
   107  	}
   108  
   109  	return *r, nil
   110  }
   111  
   112  func (s *TotalTokenWeightedDefault) GetVoteWeightForBalance(
   113  	vote *models.VoteWithBalance,
   114  	proposal *models.Proposal,
   115  ) (float64, error) {
   116  	var weight float64
   117  	var ERROR error = fmt.Errorf("no weight found, address: %s, strategy: %s", vote.Addr, *proposal.Strategy)
   118  
   119  	totalBalance := float64(*vote.StakingBalance) + float64(*vote.PrimaryAccountBalance) + float64(*vote.SecondaryAccountBalance)
   120  
   121  	weight = totalBalance * math.Pow(10, -8)
   122  
   123  	switch {
   124  	case proposal.Max_weight != nil && weight > *proposal.Max_weight:
   125  		weight = *proposal.Max_weight
   126  		return weight, nil
   127  	case proposal.Max_weight != nil && weight < *proposal.Max_weight:
   128  		return weight, nil
   129  	case weight > 0.00:
   130  		return weight, nil
   131  	case weight == 0.00:
   132  		return 0.00, nil
   133  	default:
   134  		return weight, ERROR
   135  	}
   136  }
   137  
   138  func (s *TotalTokenWeightedDefault) GetVotes(
   139  	votes []*models.VoteWithBalance,
   140  	proposal *models.Proposal,
   141  ) ([]*models.VoteWithBalance, error) {
   142  
   143  	for _, vote := range votes {
   144  		weight, err := s.GetVoteWeightForBalance(vote, proposal)
   145  		if err != nil {
   146  			return nil, err
   147  		}
   148  		vote.Weight = &weight
   149  	}
   150  
   151  	return votes, nil
   152  }
   153  
   154  func (s *TotalTokenWeightedDefault) RequiresSnapshot() bool {
   155  	return true
   156  }
   157  
   158  func (s *TotalTokenWeightedDefault) InitStrategy(
   159  	f *shared.FlowAdapter,
   160  	db *shared.Database,
   161  ) {
   162  	s.FlowAdapter = f
   163  	s.DB = db
   164  }